[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.
"-fmodules",
// Enable implicit module maps
// Enable implicit module maps (this option is implied by "-fmodules").
"-fimplicit-module-maps",
// Don't emit LLVM IR.
@@ -358,6 +358,35 @@ getNormalInvocationArguments(std::vector<std::string> &invocationArgStrs,
// Just use the most feature-rich C language mode.
"-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()) {

View File

@@ -31,6 +31,7 @@ if(SWIFT_BUILD_STDLIB)
add_subdirectory(stubs)
add_subdirectory(core)
add_subdirectory(SwiftOnoneSupport)
add_subdirectory(Glibc)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
@@ -38,7 +39,3 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
add_subdirectory(SDK)
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
)
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
set(GLIBC_INCLUDE_PATH "/usr/include")
if(CMAKE_LIBRARY_ARCHITECTURE)
set(GLIBC_ARCH_INCLUDE_PATH "${GLIBC_INCLUDE_PATH}/${CMAKE_LIBRARY_ARCHITECTURE}")
else()
set(GLIBC_ARCH_INCLUDE_PATH "${GLIBC_INCLUDE_PATH}")
endif()
if (NOT EXISTS "${GLIBC_ARCH_INCLUDE_PATH}/sys")
message(FATAL_ERROR "Glibc headers were not found.")
endif()
# Determine the location of glibc based on the target.
set(GLIBC_INCLUDE_PATH "/usr/include")
set(GLIBC_ARCH_INCLUDE_PATH "${GLIBC_INCLUDE_PATH}")
if(("${SDK}" STREQUAL "LINUX" OR "${SDK}" STREQUAL "FREEBSD") AND CMAKE_LIBRARY_ARCHITECTURE)
# FIXME: Some distributions install headers in
# "/usr/include/x86_64-linux-gnu/sys/...". Here we use the host
# machine's path, regardless of the SDK target we're building for.
# This will break if cross-compiling from a distro that uses the
# architecture as part of the path to a distro that does not.
set(GLIBC_ARCH_INCLUDE_PATH "${GLIBC_INCLUDE_PATH}/${CMAKE_LIBRARY_ARCHITECTURE}")
endif()
# Generate module.map
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
configure_file(module.map.in "${CMAKE_CURRENT_BINARY_DIR}/module.map" @ONLY)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
configure_file(module.freebsd.map.in "${CMAKE_CURRENT_BINARY_DIR}/module.map" @ONLY)
endif()
# Configure the modulemap based on the target. Each platform needs to
# reference different headers, based on what's available in their glibc.
set(modulemap_path "${CMAKE_CURRENT_BINARY_DIR}/${SWIFT_SDK_${SDK}_LIB_SUBDIR}/${arch}/module.map")
if("${SDK}" STREQUAL "FREEBSD")
configure_file(module.freebsd.map.in "${modulemap_path}" @ONLY)
else()
configure_file(module.map.in "${modulemap_path}" @ONLY)
endif()
add_custom_command_target(unused_var
COMMAND
"${CMAKE_COMMAND}" "-E" "make_directory" "${output_dir}"
COMMAND
"${CMAKE_COMMAND}" "-E" "copy_if_different"
"${CMAKE_CURRENT_BINARY_DIR}/module.map"
"${output_dir}/module.map"
CUSTOM_TARGET_NAME "copy_glibc_module"
OUTPUT "${output_dir}/module.map" "${output_dir}"
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/module.map"
COMMENT "Copying Glibc module to ${output_dir}")
set(VARIANT_SUFFIX "-${SWIFT_SDK_${SDK}_LIB_SUBDIR}-${arch}")
add_custom_command_target(unused_var
COMMAND
"${CMAKE_COMMAND}" "-E" "make_directory" "${output_dir}"
COMMAND
"${CMAKE_COMMAND}" "-E" "copy_if_different"
"${modulemap_path}"
"${output_dir}/glibc.modulemap"
CUSTOM_TARGET_NAME "copy_glibc_module${VARIANT_SUFFIX}"
OUTPUT "${output_dir}/glibc.modulemap" "${output_dir}"
DEPENDS "${modulemap_path}"
COMMENT "Copying Glibc module to ${output_dir}")
swift_install_in_component(stdlib
FILES "${output_dir}/module.map"
DESTINATION "lib/swift/glibc")
swift_install_in_component(stdlib
FILES "${output_dir}/glibc.modulemap"
DESTINATION "${output_dir}")
add_swift_library(swiftGlibc IS_SDK_OVERLAY
${sources}
FILE_DEPENDS copy_glibc_module "${output_dir}"
INSTALL_IN_COMPONENT stdlib-experimental)
if("${SDK}" STREQUAL "LINUX" OR "${SDK}" STREQUAL "${FREEBSD}")
add_swift_library(swiftGlibc IS_SDK_OVERLAY
${sources}
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;
}
// 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;
LangOptions LangOpts;
SearchPathOptions SearchPathOpts;
LangOpts.Target = Invocation.getTargetTriple();
ASTContext ASTCtx(LangOpts, SearchPathOpts, SrcMgr, Instance.getDiags());
ClangImporterOptions ClangImporterOpts;