[Glibc] Configure modulemap for target, not host

The current Glibc CMakeLists.txt uses the host machine to determine
which modulemap to use. The same modulemap can't be used for all
platforms because headers are available in different locations on
different platforms.

Using the host machine to determine which modulemap to configure and
place at a specific path in the resource dir is fine, so long as:

1. Only one Glibc is being compiled in a single CMake invocation.
2. The target machine needs the same modulemap as the host.

https://github.com/apple/swift/pull/1442 violates both of these
assumptions: the Glibc module for both Linux and Android is compiled
at the same time, and the Android target can't use the Linux modulemap.

This commit instead uses the target(s) to determine which
modulemap to use. The modulemap is configured and placed in an OS-
and architecture-specific directory in the resource dir. The path to
that modulemap is referenced by the ClangImporter (since it is no
longer at a path that is automatically discovered as an implicit
modulemap).
This commit is contained in:
Brian Gesiak
2016-03-12 14:15:32 -05:00
committed by Brian Gesiak
parent 7318060242
commit 04e1cd5bda
4 changed files with 91 additions and 43 deletions

View File

@@ -295,7 +295,7 @@ getNormalInvocationArguments(std::vector<std::string> &invocationArgStrs,
// Enable modules. // Enable modules.
"-fmodules", "-fmodules",
// Enable implicit module maps // Enable implicit module maps (this option is implied by "-fmodules").
"-fimplicit-module-maps", "-fimplicit-module-maps",
// Don't emit LLVM IR. // Don't emit LLVM IR.
@@ -358,6 +358,35 @@ getNormalInvocationArguments(std::vector<std::string> &invocationArgStrs,
// Just use the most feature-rich C language mode. // Just use the most feature-rich C language mode.
"-x", "c", "-std=gnu11", "-x", "c", "-std=gnu11",
}); });
// The module map used for Glibc depends on the target we're compiling for,
// and is not included in the resource directory with the other implicit
// module maps. It's at {freebsd|linux}/{arch}/glibc.modulemap.
SmallString<128> GlibcModuleMapPath;
if (!importerOpts.OverrideResourceDir.empty()) {
GlibcModuleMapPath = importerOpts.OverrideResourceDir;
} else if (!searchPathOpts.RuntimeResourcePath.empty()) {
GlibcModuleMapPath = searchPathOpts.RuntimeResourcePath;
}
// Running without a resource directory is not a supported configuration.
assert(!GlibcModuleMapPath.empty());
llvm::sys::path::append(
GlibcModuleMapPath,
swift::getPlatformNameForTriple(triple), triple.getArchName(),
"glibc.modulemap");
// Only specify the module map if that file actually exists.
// It may not--for example in the case that
// `swiftc -target x86_64-unknown-linux-gnu -emit-ir` is invoked using
// a Swift compiler not built for Linux targets.
if (llvm::sys::fs::exists(GlibcModuleMapPath)) {
invocationArgStrs.push_back(
(Twine("-fmodule-map-file=") + GlibcModuleMapPath).str());
} else {
// FIXME: Emit a warning of some kind.
}
} }
if (triple.isOSDarwin()) { if (triple.isOSDarwin()) {

View File

@@ -31,6 +31,7 @@ if(SWIFT_BUILD_STDLIB)
add_subdirectory(stubs) add_subdirectory(stubs)
add_subdirectory(core) add_subdirectory(core)
add_subdirectory(SwiftOnoneSupport) add_subdirectory(SwiftOnoneSupport)
add_subdirectory(Glibc)
endif() endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
@@ -38,7 +39,3 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
add_subdirectory(SDK) add_subdirectory(SDK)
endif() endif()
endif() endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
add_subdirectory(Glibc)
endif()

View File

@@ -3,44 +3,56 @@ set(sources
Misc.c Misc.c
) )
set(output_dir "${SWIFTLIB_DIR}/glibc") # When cross-compiling the stdlib on Unix platforms, we'll need a separate
# glibc for each target.
foreach(SDK ${SWIFT_SDKS})
foreach(arch ${SWIFT_SDK_${SDK}_ARCHITECTURES})
set(output_dir "${SWIFTLIB_DIR}/${SWIFT_SDK_${SDK}_LIB_SUBDIR}/${arch}")
# Set correct paths to glibc headers # Determine the location of glibc based on the target.
set(GLIBC_INCLUDE_PATH "/usr/include") set(GLIBC_INCLUDE_PATH "/usr/include")
if(CMAKE_LIBRARY_ARCHITECTURE) set(GLIBC_ARCH_INCLUDE_PATH "${GLIBC_INCLUDE_PATH}")
set(GLIBC_ARCH_INCLUDE_PATH "${GLIBC_INCLUDE_PATH}/${CMAKE_LIBRARY_ARCHITECTURE}") if(("${SDK}" STREQUAL "LINUX" OR "${SDK}" STREQUAL "FREEBSD") AND CMAKE_LIBRARY_ARCHITECTURE)
else() # FIXME: Some distributions install headers in
set(GLIBC_ARCH_INCLUDE_PATH "${GLIBC_INCLUDE_PATH}") # "/usr/include/x86_64-linux-gnu/sys/...". Here we use the host
endif() # machine's path, regardless of the SDK target we're building for.
if (NOT EXISTS "${GLIBC_ARCH_INCLUDE_PATH}/sys") # This will break if cross-compiling from a distro that uses the
message(FATAL_ERROR "Glibc headers were not found.") # architecture as part of the path to a distro that does not.
endif() set(GLIBC_ARCH_INCLUDE_PATH "${GLIBC_INCLUDE_PATH}/${CMAKE_LIBRARY_ARCHITECTURE}")
endif()
# Generate module.map # Configure the modulemap based on the target. Each platform needs to
if(CMAKE_SYSTEM_NAME STREQUAL "Linux") # reference different headers, based on what's available in their glibc.
configure_file(module.map.in "${CMAKE_CURRENT_BINARY_DIR}/module.map" @ONLY) set(modulemap_path "${CMAKE_CURRENT_BINARY_DIR}/${SWIFT_SDK_${SDK}_LIB_SUBDIR}/${arch}/module.map")
endif() if("${SDK}" STREQUAL "FREEBSD")
if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") configure_file(module.freebsd.map.in "${modulemap_path}" @ONLY)
configure_file(module.freebsd.map.in "${CMAKE_CURRENT_BINARY_DIR}/module.map" @ONLY) else()
endif() configure_file(module.map.in "${modulemap_path}" @ONLY)
endif()
add_custom_command_target(unused_var set(VARIANT_SUFFIX "-${SWIFT_SDK_${SDK}_LIB_SUBDIR}-${arch}")
COMMAND add_custom_command_target(unused_var
"${CMAKE_COMMAND}" "-E" "make_directory" "${output_dir}" COMMAND
COMMAND "${CMAKE_COMMAND}" "-E" "make_directory" "${output_dir}"
"${CMAKE_COMMAND}" "-E" "copy_if_different" COMMAND
"${CMAKE_CURRENT_BINARY_DIR}/module.map" "${CMAKE_COMMAND}" "-E" "copy_if_different"
"${output_dir}/module.map" "${modulemap_path}"
CUSTOM_TARGET_NAME "copy_glibc_module" "${output_dir}/glibc.modulemap"
OUTPUT "${output_dir}/module.map" "${output_dir}" CUSTOM_TARGET_NAME "copy_glibc_module${VARIANT_SUFFIX}"
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/module.map" OUTPUT "${output_dir}/glibc.modulemap" "${output_dir}"
COMMENT "Copying Glibc module to ${output_dir}") DEPENDS "${modulemap_path}"
COMMENT "Copying Glibc module to ${output_dir}")
swift_install_in_component(stdlib swift_install_in_component(stdlib
FILES "${output_dir}/module.map" FILES "${output_dir}/glibc.modulemap"
DESTINATION "lib/swift/glibc") DESTINATION "${output_dir}")
add_swift_library(swiftGlibc IS_SDK_OVERLAY if("${SDK}" STREQUAL "LINUX" OR "${SDK}" STREQUAL "${FREEBSD}")
${sources} add_swift_library(swiftGlibc IS_SDK_OVERLAY
FILE_DEPENDS copy_glibc_module "${output_dir}" ${sources}
INSTALL_IN_COMPONENT stdlib-experimental) FILE_DEPENDS "copy_glibc_module${VARIANT_SUFFIX}" "${output_dir}"
TARGET_SDKS "${SDK}"
INSTALL_IN_COMPONENT stdlib-experimental)
endif()
endforeach()
endforeach()

View File

@@ -153,10 +153,20 @@ int modulewrap_main(ArrayRef<const char *> Args, const char *Argv0,
return 1; return 1;
} }
// Wrap the bitstream in an object file. // Wrap the bitstream in a module object file. To use the ClangImporter to
// create the module loader, we need to properly set the runtime library path.
SearchPathOptions SearchPathOpts;
// FIXME: This logic has been duplicated from
// CompilerInvocation::setMainExecutablePath. ModuleWrapInvocation
// should share its implementation.
SmallString<128> RuntimeResourcePath(MainExecutablePath);
llvm::sys::path::remove_filename(RuntimeResourcePath); // Remove /swift
llvm::sys::path::remove_filename(RuntimeResourcePath); // Remove /bin
llvm::sys::path::append(RuntimeResourcePath, "lib", "swift");
SearchPathOpts.RuntimeResourcePath = RuntimeResourcePath.str();
SourceManager SrcMgr; SourceManager SrcMgr;
LangOptions LangOpts; LangOptions LangOpts;
SearchPathOptions SearchPathOpts;
LangOpts.Target = Invocation.getTargetTriple(); LangOpts.Target = Invocation.getTargetTriple();
ASTContext ASTCtx(LangOpts, SearchPathOpts, SrcMgr, Instance.getDiags()); ASTContext ASTCtx(LangOpts, SearchPathOpts, SrcMgr, Instance.getDiags());
ClangImporterOptions ClangImporterOpts; ClangImporterOptions ClangImporterOpts;