Skip to content
This repository was archived by the owner on Nov 10, 2023. It is now read-only.

Commit 89981e5

Browse files
natestedmanfacebook-github-bot
authored andcommitted
Allow creation of an "umbrella directory" module map
Summary: This adds a separate mode for module map generation that uses an umbrella directory declaration, rather than an umbrella header declaration. This fits Buck's general approach to headers better - it's kind of like an autoglob for every header in the library, without the need to either generate or manually maintain a valid umbrella header. It's implemented by adding a new `ModuleMapMode` enum, and a new case to `HeaderMode` to differentiate between the two associated forms of module maps. I decided to have it specified at the `.buckconfig` level, rather than per-library, as this is simpler and is sufficient for the use-case. Reviewed By: williamtwilson shipit-source-id: 10842bbd24
1 parent ef8007c commit 89981e5

33 files changed

+436
-27
lines changed

src/com/facebook/buck/apple/AppleConfig.java

+8
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.facebook.buck.apple;
1818

19+
import com.facebook.buck.apple.clang.ModuleMapMode;
1920
import com.facebook.buck.apple.toolchain.ApplePlatform;
2021
import com.facebook.buck.core.config.BuckConfig;
2122
import com.facebook.buck.core.config.ConfigView;
@@ -462,6 +463,13 @@ public boolean shouldWorkAroundDsymutilLTOStackOverflowBug() {
462463
APPLE_SECTION, "work_around_dsymutil_lto_stack_overflow_bug", false);
463464
}
464465

466+
/** @return The module map mode to use for modular libraries. */
467+
public ModuleMapMode moduleMapMode() {
468+
return delegate
469+
.getEnum(APPLE_SECTION, "modulemap_mode", ModuleMapMode.class)
470+
.orElse(ModuleMapMode.UMBRELLA_HEADER);
471+
}
472+
465473
public Path shellPath() {
466474
return delegate.getPath(APPLE_SECTION, "xcode_build_script_shell").orElse(Paths.get("/bin/sh"));
467475
}

src/com/facebook/buck/apple/AppleLibraryDescription.java

+8-4
Original file line numberDiff line numberDiff line change
@@ -635,7 +635,7 @@ BuildRule requireSingleArchUnstrippedBuildRule(
635635
&& libType.isPresent()
636636
&& libType.get().equals(Type.EXPORTED_HEADERS)
637637
&& headerMode.isPresent()
638-
&& headerMode.get().equals(HeaderMode.SYMLINK_TREE_WITH_MODULEMAP)) {
638+
&& headerMode.get().includesModuleMap()) {
639639
return createExportedModuleSymlinkTreeBuildRule(
640640
buildTarget,
641641
context.getProjectFilesystem(),
@@ -711,7 +711,7 @@ private HeaderSymlinkTree createExportedModuleSymlinkTreeBuildRule(
711711
return CxxDescriptionEnhancer.createHeaderSymlinkTree(
712712
buildTarget,
713713
projectFilesystem,
714-
HeaderMode.SYMLINK_TREE_WITH_MODULEMAP,
714+
HeaderMode.forModuleMapMode(appleConfig.moduleMapMode()),
715715
headers.build(),
716716
HeaderVisibility.PUBLIC);
717717
}
@@ -733,7 +733,11 @@ private HeaderSymlinkTree createUnderlyingModuleSymlinkTreeBuildRule(
733733

734734
Path root = BuildTargetPaths.getGenPath(projectFilesystem, buildTarget, "%s");
735735
return CxxPreprocessables.createHeaderSymlinkTreeBuildRule(
736-
buildTarget, projectFilesystem, root, headers, HeaderMode.SYMLINK_TREE_WITH_MODULEMAP);
736+
buildTarget,
737+
projectFilesystem,
738+
root,
739+
headers,
740+
HeaderMode.forModuleMapMode(appleConfig.moduleMapMode()));
737741
}
738742

739743
<U> Optional<U> createMetadataForLibrary(
@@ -910,7 +914,7 @@ private <U> Optional<U> createCxxPreprocessorInputMetadata(
910914
.withAppendedFlavors(
911915
CxxLibraryDescription.Type.EXPORTED_HEADERS.getFlavor(),
912916
platformEntry.getKey(),
913-
HeaderMode.SYMLINK_TREE_WITH_MODULEMAP.getFlavor()));
917+
HeaderMode.forModuleMapMode(appleConfig.moduleMapMode()).getFlavor()));
914918
cxxPreprocessorInputBuilder.addIncludes(
915919
CxxSymlinkTreeHeaders.from(symlinkTree, CxxPreprocessables.IncludeType.LOCAL));
916920
CxxPreprocessorInput cxxPreprocessorInput = cxxPreprocessorInputBuilder.build();

src/com/facebook/buck/apple/BUCK

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ java_library_with_plugins(
2020
],
2121
deps = [
2222
"//src/com/facebook/buck/android/toolchain/ndk:ndk",
23+
"//src/com/facebook/buck/apple/clang:clang",
2324
"//src/com/facebook/buck/apple/platform_type:type",
2425
"//src/com/facebook/buck/apple/simulator:simulator",
2526
"//src/com/facebook/buck/apple/toolchain:toolchain",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright 2014-present Facebook, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may
5+
* not use this file except in compliance with the License. You may obtain
6+
* a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
17+
package com.facebook.buck.apple.clang;
18+
19+
/**
20+
* Creates module map instances.
21+
*
22+
* <p>Use this instead of directly creating UmbrellaHeaderModuleMap or UmbrellaDirectoryModuleMap
23+
* instances.
24+
*/
25+
public class ModuleMapFactory {
26+
27+
/**
28+
* Creates a module map.
29+
*
30+
* @param moduleName The name of the module.
31+
* @param moduleMapMode The module map mode to use.
32+
* @param swiftMode The Swift mode to use for umbrella header module maps. This parameter is
33+
* unused with umbrella directory module maps.
34+
* @return A module map instance.
35+
*/
36+
public static ModuleMap createModuleMap(
37+
String moduleName, ModuleMapMode moduleMapMode, UmbrellaHeaderModuleMap.SwiftMode swiftMode) {
38+
switch (moduleMapMode) {
39+
case UMBRELLA_HEADER:
40+
return new UmbrellaHeaderModuleMap(moduleName, swiftMode);
41+
case UMBRELLA_DIRECTORY:
42+
return new UmbrellaDirectoryModuleMap(moduleName);
43+
}
44+
45+
throw new RuntimeException();
46+
}
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2014-present Facebook, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may
5+
* not use this file except in compliance with the License. You may obtain
6+
* a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
17+
package com.facebook.buck.apple.clang;
18+
19+
/** Enumerates the module map generation modes that Buck supports. */
20+
public enum ModuleMapMode {
21+
/** Generate a module map that requires an umbrella header. */
22+
UMBRELLA_HEADER,
23+
24+
/** Generate a module map that uses the library's headers in an umbrella directory. */
25+
UMBRELLA_DIRECTORY,
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright 2014-present Facebook, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may
5+
* not use this file except in compliance with the License. You may obtain
6+
* a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
17+
package com.facebook.buck.apple.clang;
18+
19+
import com.google.common.base.Objects;
20+
import javax.annotation.Nullable;
21+
import org.stringtemplate.v4.ST;
22+
23+
/**
24+
* A module map using an umbrella directory, rather than an umbrella header. This removes the need
25+
* to maintain or generate an umbrella header: all exported headers in the library will be included
26+
* in the module automatically.
27+
*/
28+
public class UmbrellaDirectoryModuleMap implements ModuleMap {
29+
private final String moduleName;
30+
31+
@Nullable private String generatedModule;
32+
private static final String template =
33+
"module <module_name> {\n"
34+
+ " umbrella \".\"\n"
35+
+ "\n"
36+
+ " module * { export * }\n"
37+
+ "}\n"
38+
+ "\n";
39+
40+
public UmbrellaDirectoryModuleMap(String moduleName) {
41+
this.moduleName = moduleName;
42+
}
43+
44+
@Override
45+
public String render() {
46+
if (this.generatedModule == null) {
47+
ST st = new ST(template).add("module_name", moduleName);
48+
this.generatedModule = st.render();
49+
}
50+
return this.generatedModule;
51+
}
52+
53+
@Override
54+
public boolean equals(Object obj) {
55+
if (!(obj instanceof UmbrellaDirectoryModuleMap)) {
56+
return false;
57+
}
58+
UmbrellaDirectoryModuleMap that = (UmbrellaDirectoryModuleMap) obj;
59+
return Objects.equal(this.moduleName, that.moduleName);
60+
}
61+
62+
@Override
63+
public int hashCode() {
64+
return Objects.hashCode(moduleName);
65+
}
66+
}

src/com/facebook/buck/cxx/CxxPreprocessables.java

+7-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.facebook.buck.cxx;
1818

19+
import com.facebook.buck.apple.clang.ModuleMapMode;
1920
import com.facebook.buck.core.model.BuildTarget;
2021
import com.facebook.buck.core.rules.ActionGraphBuilder;
2122
import com.facebook.buck.core.rules.BuildRule;
@@ -138,8 +139,12 @@ public static HeaderSymlinkTree createHeaderSymlinkTreeBuildRule(
138139
switch (headerMode) {
139140
case SYMLINK_TREE_WITH_HEADER_MAP:
140141
return HeaderSymlinkTreeWithHeaderMap.create(target, filesystem, root, links);
141-
case SYMLINK_TREE_WITH_MODULEMAP:
142-
return HeaderSymlinkTreeWithModuleMap.create(target, filesystem, root, links);
142+
case SYMLINK_TREE_WITH_UMBRELLA_HEADER_MODULEMAP:
143+
return HeaderSymlinkTreeWithModuleMap.create(
144+
target, filesystem, root, links, ModuleMapMode.UMBRELLA_HEADER);
145+
case SYMLINK_TREE_WITH_UMBRELLA_DIRECTORY_MODULEMAP:
146+
return HeaderSymlinkTreeWithModuleMap.create(
147+
target, filesystem, root, links, ModuleMapMode.UMBRELLA_DIRECTORY);
143148
case HEADER_MAP_ONLY:
144149
return new DirectHeaderMap(target, filesystem, root, links);
145150
default:

src/com/facebook/buck/cxx/toolchain/HeaderMode.java

+46-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.facebook.buck.cxx.toolchain;
1818

19+
import com.facebook.buck.apple.clang.ModuleMapMode;
1920
import com.facebook.buck.core.model.Flavor;
2021
import com.facebook.buck.core.model.FlavorConvertible;
2122
import com.facebook.buck.core.model.InternalFlavor;
@@ -34,9 +35,16 @@ public enum HeaderMode implements FlavorConvertible {
3435
SYMLINK_TREE_WITH_HEADER_MAP,
3536
/**
3637
* Creates the tree of symbolic links of headers and creates a module map that references the
37-
* symbolic links to the headers.
38+
* symbolic links to the headers. The generated module map will refer to an umbrella header, with
39+
* the same name as the library.
40+
*/
41+
SYMLINK_TREE_WITH_UMBRELLA_HEADER_MODULEMAP,
42+
/**
43+
* Creates the tree of symbolic links of headers and creates a module map that references the
44+
* symbolic links to the headers. The generated module map will refer to an umbrella directory,
45+
* avoiding the need for a valid and complete umbrella header.
3846
*/
39-
SYMLINK_TREE_WITH_MODULEMAP,
47+
SYMLINK_TREE_WITH_UMBRELLA_DIRECTORY_MODULEMAP,
4048
;
4149

4250
private final Flavor flavor;
@@ -54,4 +62,40 @@ public enum HeaderMode implements FlavorConvertible {
5462
public Flavor getFlavor() {
5563
return flavor;
5664
}
65+
66+
/**
67+
* Returns the appropriate header mode for module map mode.
68+
*
69+
* @param moduleMapMode The module map mode to convert.
70+
* @return The equivalent header mode.
71+
*/
72+
public static HeaderMode forModuleMapMode(ModuleMapMode moduleMapMode) {
73+
switch (moduleMapMode) {
74+
case UMBRELLA_HEADER:
75+
return SYMLINK_TREE_WITH_UMBRELLA_HEADER_MODULEMAP;
76+
case UMBRELLA_DIRECTORY:
77+
return SYMLINK_TREE_WITH_UMBRELLA_DIRECTORY_MODULEMAP;
78+
}
79+
80+
throw new RuntimeException("Unexpected value of enum ModuleMapMode");
81+
}
82+
83+
/**
84+
* Returns whether or not the header mode will include a module map.
85+
*
86+
* @return true if the header mode will include a module map, otherwise false.
87+
*/
88+
public boolean includesModuleMap() {
89+
switch (this) {
90+
case SYMLINK_TREE_ONLY:
91+
case SYMLINK_TREE_WITH_HEADER_MAP:
92+
case HEADER_MAP_ONLY:
93+
return false;
94+
case SYMLINK_TREE_WITH_UMBRELLA_HEADER_MODULEMAP:
95+
case SYMLINK_TREE_WITH_UMBRELLA_DIRECTORY_MODULEMAP:
96+
return true;
97+
}
98+
99+
throw new RuntimeException("Unexpected value of enum HeaderMode");
100+
}
57101
}

src/com/facebook/buck/cxx/toolchain/HeaderSymlinkTreeWithModuleMap.java

+12-4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package com.facebook.buck.cxx.toolchain;
1818

19+
import com.facebook.buck.apple.clang.ModuleMapFactory;
20+
import com.facebook.buck.apple.clang.ModuleMapMode;
1921
import com.facebook.buck.apple.clang.UmbrellaHeader;
2022
import com.facebook.buck.apple.clang.UmbrellaHeaderModuleMap;
2123
import com.facebook.buck.core.build.buildable.context.BuildableContext;
@@ -38,24 +40,29 @@
3840
public final class HeaderSymlinkTreeWithModuleMap extends HeaderSymlinkTree {
3941

4042
@AddToRuleKey private final Optional<String> moduleName;
43+
@AddToRuleKey private final ModuleMapMode moduleMapMode;
4144

4245
private HeaderSymlinkTreeWithModuleMap(
4346
BuildTarget target,
4447
ProjectFilesystem filesystem,
4548
Path root,
4649
ImmutableMap<Path, SourcePath> links,
47-
Optional<String> moduleName) {
50+
Optional<String> moduleName,
51+
ModuleMapMode moduleMapMode) {
4852
super(target, filesystem, root, links);
4953
this.moduleName = moduleName;
54+
this.moduleMapMode = moduleMapMode;
5055
}
5156

5257
public static HeaderSymlinkTreeWithModuleMap create(
5358
BuildTarget target,
5459
ProjectFilesystem filesystem,
5560
Path root,
56-
ImmutableMap<Path, SourcePath> links) {
61+
ImmutableMap<Path, SourcePath> links,
62+
ModuleMapMode moduleMapMode) {
5763
Optional<String> moduleName = getModuleName(links);
58-
return new HeaderSymlinkTreeWithModuleMap(target, filesystem, root, links, moduleName);
64+
return new HeaderSymlinkTreeWithModuleMap(
65+
target, filesystem, root, links, moduleName, moduleMapMode);
5966
}
6067

6168
@Override
@@ -81,8 +88,9 @@ public ImmutableList<Step> getBuildSteps(
8188
new ModuleMapStep(
8289
getProjectFilesystem(),
8390
moduleMapPath(getProjectFilesystem(), getBuildTarget(), moduleName),
84-
new UmbrellaHeaderModuleMap(
91+
ModuleMapFactory.createModuleMap(
8592
moduleName,
93+
moduleMapMode,
8694
containsSwiftHeader(paths, moduleName)
8795
? UmbrellaHeaderModuleMap.SwiftMode.INCLUDE_SWIFT_HEADER
8896
: UmbrellaHeaderModuleMap.SwiftMode.NO_SWIFT)));

0 commit comments

Comments
 (0)