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;