Skip to content
This repository has been archived by the owner on Jan 2, 2021. It is now read-only.

Commit

Permalink
Automatically import underlying Objective-C modules into Swift. Fixes #…
Browse files Browse the repository at this point in the history
…92.

Frameworks expect that their underlying Objective-C module is available
in Swift without an explicit bridging header. In order to support that,
a custom module map is needed at build time and an additional flag tells
the Swift compiler to import the underlying module automatically.
  • Loading branch information
grp committed Sep 1, 2016
1 parent 8957c23 commit a07f339
Showing 1 changed file with 72 additions and 0 deletions.
72 changes: 72 additions & 0 deletions Libraries/pbxbuild/Sources/Tool/SwiftResolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,73 @@ AppendObjcHeader(
}
}

static void
AppendUnderlyingModule(
std::vector<std::string> *args,
std::vector<Tool::Invocation::AuxiliaryFile> *auxiliaryFiles,
Tool::Context const *toolContext,
pbxsetting::Environment const &environment,
std::string const &headerName)
{
/* No module map means no underlying module to import. */
ext::optional<Tool::ModuleMapInfo::Entry> const &moduleMap = toolContext->moduleMapInfo().moduleMap();
if (!moduleMap) {
return;
}

/*
* Create a module map to import the underlying module. However, exclude the Swift-generated
* header here, to avoid having this module try and import its own generated Objective-C structures.
*/
std::string moduleName = environment.resolve("PRODUCT_MODULE_NAME");

std::string unextendedModuleMap = "\n";
unextendedModuleMap += "module " + moduleName + ".__Swift {\n";
unextendedModuleMap += " exclude header \"" + headerName + "\"\n";
unextendedModuleMap += "}\n";

auto unextendedModuleMapData = std::vector<uint8_t>(unextendedModuleMap.begin(), unextendedModuleMap.end());
auto unextendedModuleMapChunk = Tool::Invocation::AuxiliaryFile::Chunk::Data(unextendedModuleMapData);

std::string unextendedModuleMapPath = environment.resolve("TARGET_TEMP_DIR") + "/" + "unextended-module.modulemap";
auto unextendedModuleMapFile = Tool::Invocation::AuxiliaryFile(unextendedModuleMapPath, { moduleMap->contents(), unextendedModuleMapChunk });
auxiliaryFiles->push_back(unextendedModuleMapFile);

/*
* Create a VFS overlay to load the above module map. This replaces the module map in the product,
* which does not contain the extra Swift rule, and may not even exist yet (depending on ordering).
*/
std::string unextendedModuleOverlayPath = environment.resolve("TARGET_TEMP_DIR") + "/" + "unextended-module-overlay.yaml";

std::string unextendedModuleOverlay;
unextendedModuleOverlay += "{\n";
unextendedModuleOverlay += " 'version': 0,\n";
unextendedModuleOverlay += " 'case-sensitive': 'false',\n";
unextendedModuleOverlay += " 'roots': [{\n";
unextendedModuleOverlay += " 'type': 'directory',\n";
unextendedModuleOverlay += " 'name': '" + FSUtil::GetDirectoryName(moduleMap->finalPath()) + "',\n";
unextendedModuleOverlay += " 'contents': [{\n";
unextendedModuleOverlay += " 'type': 'file',\n";
unextendedModuleOverlay += " 'name': '" + FSUtil::GetBaseName(moduleMap->finalPath()) + "',\n";
unextendedModuleOverlay += " 'external-contents': '" + unextendedModuleMapPath + "',\n";
unextendedModuleOverlay += " }]\n";
unextendedModuleOverlay += " }]\n";
unextendedModuleOverlay += "}\n";

auto unextendedModuleOverlayData = std::vector<uint8_t>(unextendedModuleOverlay.begin(), unextendedModuleOverlay.end());
auto unextendedModuleOverlayFile = Tool::Invocation::AuxiliaryFile::Data(unextendedModuleOverlayPath, unextendedModuleOverlayData);
auxiliaryFiles->push_back(unextendedModuleOverlayFile);

/*
* Add flags to import the underlying module.
*/
args->push_back("-import-underlying-module");
args->push_back("-Xcc");
args->push_back("-ivfsoverlay");
args->push_back("-Xcc");
args->push_back(unextendedModuleOverlayPath);
}

void Tool::SwiftResolver::
resolve(
Tool::Context *toolContext,
Expand Down Expand Up @@ -312,6 +379,11 @@ resolve(
std::string headerPath = outputDirectory + "/" + headerName;
AppendObjcHeader(&arguments, &outputs, environment, outputDirectory, headerName, headerPath);

/*
* Automatically import the underlying Objective-C module if available.
*/
AppendUnderlyingModule(&arguments, &auxiliaryFiles, toolContext, environment, headerName);

/* Compiler working directory. */
arguments.push_back("-Xcc");
arguments.push_back("-working-directory" + toolContext->workingDirectory());
Expand Down

0 comments on commit a07f339

Please sign in to comment.