From 04e1cd5bda40eb494385fa9c71ce22b8100a2d4b Mon Sep 17 00:00:00 2001 From: Brian Gesiak Date: Sat, 12 Mar 2016 14:15:32 -0500 Subject: [PATCH] [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). --- lib/ClangImporter/ClangImporter.cpp | 31 ++++++++++- stdlib/public/CMakeLists.txt | 5 +- stdlib/public/Glibc/CMakeLists.txt | 84 ++++++++++++++++------------- tools/driver/modulewrap_main.cpp | 14 ++++- 4 files changed, 91 insertions(+), 43 deletions(-) diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 6595e1e1eea1a..8c808a5bae253 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -295,7 +295,7 @@ getNormalInvocationArguments(std::vector &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 &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()) { diff --git a/stdlib/public/CMakeLists.txt b/stdlib/public/CMakeLists.txt index 7cc7be641cdbb..3cd6cd23a471b 100644 --- a/stdlib/public/CMakeLists.txt +++ b/stdlib/public/CMakeLists.txt @@ -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() diff --git a/stdlib/public/Glibc/CMakeLists.txt b/stdlib/public/Glibc/CMakeLists.txt index d7e277b69e260..abda4ebb0248c 100644 --- a/stdlib/public/Glibc/CMakeLists.txt +++ b/stdlib/public/Glibc/CMakeLists.txt @@ -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() diff --git a/tools/driver/modulewrap_main.cpp b/tools/driver/modulewrap_main.cpp index 6e8489ed51bbb..9c4e3fa036b2c 100644 --- a/tools/driver/modulewrap_main.cpp +++ b/tools/driver/modulewrap_main.cpp @@ -153,10 +153,20 @@ int modulewrap_main(ArrayRef 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;