Skip to content

[cxx-interop] Import libstdc++ as a Clang module #41953

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 31 additions & 10 deletions lib/ClangImporter/ClangImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -430,14 +430,10 @@ ClangImporter::~ClangImporter() {

#pragma mark Module loading

/// Finds the glibc.modulemap file relative to the provided resource dir.
///
/// Note that 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.
static Optional<StringRef>
getGlibcModuleMapPath(SearchPathOptions& Opts, llvm::Triple triple,
SmallVectorImpl<char> &buffer) {
static Optional<StringRef> getModuleMapFilePath(StringRef name,
SearchPathOptions &Opts,
llvm::Triple triple,
SmallVectorImpl<char> &buffer) {
StringRef platform = swift::getPlatformNameForTriple(triple);
StringRef arch = swift::getMajorArchitectureName(triple);

Expand All @@ -446,7 +442,7 @@ getGlibcModuleMapPath(SearchPathOptions& Opts, llvm::Triple triple,
buffer.clear();
buffer.append(SDKPath.begin(), SDKPath.end());
llvm::sys::path::append(buffer, "usr", "lib", "swift");
llvm::sys::path::append(buffer, platform, arch, "glibc.modulemap");
llvm::sys::path::append(buffer, platform, arch, name);

// 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
Expand All @@ -459,7 +455,7 @@ getGlibcModuleMapPath(SearchPathOptions& Opts, llvm::Triple triple,
buffer.clear();
buffer.append(Opts.RuntimeResourcePath.begin(),
Opts.RuntimeResourcePath.end());
llvm::sys::path::append(buffer, platform, arch, "glibc.modulemap");
llvm::sys::path::append(buffer, platform, arch, name);

// 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
Expand All @@ -471,6 +467,23 @@ getGlibcModuleMapPath(SearchPathOptions& Opts, llvm::Triple triple,
return None;
}

/// Finds the glibc.modulemap file relative to the provided resource dir.
///
/// Note that 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.
static Optional<StringRef>
getGlibcModuleMapPath(SearchPathOptions &Opts, llvm::Triple triple,
SmallVectorImpl<char> &buffer) {
return getModuleMapFilePath("glibc.modulemap", Opts, triple, buffer);
}

static Optional<StringRef>
getLibStdCxxModuleMapPath(SearchPathOptions &opts, llvm::Triple triple,
SmallVectorImpl<char> &buffer) {
return getModuleMapFilePath("libstdcxx.modulemap", opts, triple, buffer);
}

static bool clangSupportsPragmaAttributeWithSwiftAttr() {
clang::AttributeCommonInfo swiftAttrInfo(clang::SourceRange(),
clang::AttributeCommonInfo::AT_SwiftAttr,
Expand Down Expand Up @@ -680,6 +693,14 @@ importer::getNormalInvocationArguments(
} else {
// FIXME: Emit a warning of some kind.
}

if (EnableCXXInterop) {
if (auto path =
getLibStdCxxModuleMapPath(searchPathOpts, triple, buffer)) {
invocationArgStrs.push_back(
(Twine("-fmodule-map-file=") + *path).str());
}
}
}

if (searchPathOpts.getSDKPath().empty()) {
Expand Down
1 change: 1 addition & 0 deletions stdlib/public/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ endif()

if(SWIFT_BUILD_SDK_OVERLAY OR SWIFT_BUILD_TEST_SUPPORT_MODULES)
add_subdirectory(Platform)
add_subdirectory(Cxx)
endif()

if(SWIFT_BUILD_SDK_OVERLAY)
Expand Down
97 changes: 97 additions & 0 deletions stdlib/public/Cxx/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
set(libstdcxx_modulemap_target_list)
foreach(sdk ${SWIFT_SDKS})
if(NOT "${sdk}" STREQUAL "LINUX" AND
NOT "${sdk}" STREQUAL "FREEBSD" AND
NOT "${sdk}" STREQUAL "OPENBSD" AND
NOT "${sdk}" STREQUAL "ANDROID" AND
NOT "${sdk}" STREQUAL "CYGWIN" AND
NOT "${sdk}" STREQUAL "HAIKU")
continue()
endif()

foreach(arch ${SWIFT_SDK_${sdk}_ARCHITECTURES})
set(arch_suffix "${SWIFT_SDK_${sdk}_LIB_SUBDIR}-${arch}")
set(arch_subdir "${SWIFT_SDK_${sdk}_LIB_SUBDIR}/${arch}")

set(module_dir "${SWIFTLIB_DIR}/${arch_subdir}")
set(module_dir_static "${SWIFTSTATICLIB_DIR}/${arch_subdir}")

set(libstdcxx_header "libstdcxx.h")
set(libstdcxx_header_out "${module_dir}/libstdcxx.h")
set(libstdcxx_header_out_static "${module_dir_static}/libstdcxx.h")
set(libstdcxx_modulemap "libstdcxx.modulemap")
set(libstdcxx_modulemap_out "${module_dir}/libstdcxx.modulemap")
set(libstdcxx_modulemap_out_static "${module_dir_static}/libstdcxx.modulemap")

add_custom_command_target(
copy_libstdcxx_modulemap
COMMAND
"${CMAKE_COMMAND}" "-E" "make_directory" ${module_dir}
COMMAND
"${CMAKE_COMMAND}" "-E" "copy" "${CMAKE_CURRENT_SOURCE_DIR}/${libstdcxx_modulemap}" "${libstdcxx_modulemap_out}"
OUTPUT ${libstdcxx_modulemap_out}
DEPENDS ${libstdcxx_modulemap}
COMMENT "Copying libstdcxx modulemap to resources")
list(APPEND libstdcxx_modulemap_target_list ${copy_libstdcxx_modulemap})
add_dependencies(swift-stdlib-${arch_suffix} ${copy_libstdcxx_modulemap})

add_custom_command_target(
copy_libstdcxx_header
COMMAND
"${CMAKE_COMMAND}" "-E" "make_directory" ${module_dir}
COMMAND
"${CMAKE_COMMAND}" "-E" "copy" "${CMAKE_CURRENT_SOURCE_DIR}/${libstdcxx_header}" "${libstdcxx_header_out}"
OUTPUT ${libstdcxx_header_out}
DEPENDS ${libstdcxx_header}
COMMENT "Copying libstdcxx header to resources")
list(APPEND libstdcxx_modulemap_target_list ${copy_libstdcxx_header})
add_dependencies(swift-stdlib-${arch_suffix} ${copy_libstdcxx_header})

if(SWIFT_BUILD_STATIC_STDLIB)
add_custom_command_target(
copy_libstdcxx_modulemap_static
COMMAND
"${CMAKE_COMMAND}" "-E" "make_directory" ${module_dir_static}
COMMAND
"${CMAKE_COMMAND}" "-E" "copy"
"${libstdcxx_modulemap_out}" "${libstdcxx_modulemap_out_static}"
OUTPUT ${libstdcxx_modulemap_out_static}
DEPENDS ${copy_libstdcxx_modulemap}
COMMENT "Copying libstdcxx modulemap to static resources")
list(APPEND libstdcxx_modulemap_target_list ${copy_libstdcxx_modulemap_static})
add_dependencies(swift-stdlib-${arch_suffix} ${copy_libstdcxx_modulemap_static})

add_custom_command_target(
copy_libstdcxx_header_static
COMMAND
"${CMAKE_COMMAND}" "-E" "make_directory" ${module_dir_static}
COMMAND
"${CMAKE_COMMAND}" "-E" "copy"
"${libstdcxx_header_out}" "${libstdcxx_header_out_static}"
OUTPUT ${libstdcxx_header_out_static}
DEPENDS ${copy_libstdcxx_header}
COMMENT "Copying libstdcxx header to static resources")
list(APPEND libstdcxx_modulemap_target_list ${copy_libstdcxx_header_static})
add_dependencies(swift-stdlib-${arch_suffix} ${copy_libstdcxx_header_static})
endif()

swift_install_in_component(FILES "${libstdcxx_modulemap_out}"
DESTINATION "lib/swift/${arch_subdir}"
COMPONENT sdk-overlay)
swift_install_in_component(FILES "${libstdcxx_header_out}"
DESTINATION "lib/swift/${arch_subdir}"
COMPONENT sdk-overlay)

if(SWIFT_BUILD_STATIC_STDLIB)
swift_install_in_component(FILES "${libstdcxx_modulemap_out_static}"
DESTINATION "lib/swift_static/${arch_subdir}"
COMPONENT sdk-overlay)
swift_install_in_component(FILES "${libstdcxx_header_out_static}"
DESTINATION "lib/swift_static/${arch_subdir}"
COMPONENT sdk-overlay)
endif()
endforeach()
endforeach()
add_custom_target(libstdcxx-modulemap DEPENDS ${libstdcxx_modulemap_target_list})
set_property(TARGET libstdcxx-modulemap PROPERTY FOLDER "Miscellaneous")
add_dependencies(sdk-overlay libstdcxx-modulemap)
60 changes: 60 additions & 0 deletions stdlib/public/Cxx/libstdcxx.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <utility>
#include <typeinfo>
#include <valarray>
#include <vector>
#include <array>
#include <atomic>
#include <chrono>
#include <codecvt>
#include <condition_variable>
#include <forward_list>
#include <future>
#include <initializer_list>
#include <mutex>
#include <random>
#include <ratio>
#include <regex>
#include <scoped_allocator>
#include <system_error>
#include <thread>
#include <tuple>
#include <typeindex>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <any>
#include <charconv>
#include <execution>
#include <filesystem>
#include <memory_resource>
#include <optional>
#include <string_view>
#include <variant>
23 changes: 23 additions & 0 deletions stdlib/public/Cxx/libstdcxx.modulemap
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//===--- libstdcxx.modulemap ----------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// In order to use a C++ stdlib from Swift, the stdlib needs to have a Clang
// module map. Currently libstdc++ does not have a module map. To work around
// this, Swift provides its own module map for libstdc++.
//
//===----------------------------------------------------------------------===//

module std {
header "libstdcxx.h"
requires cplusplus
export *
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,8 @@
// RUN: %target-swift-ide-test -print-module -module-to-print=std.iosfwd -source-filename=x -enable-experimental-cxx-interop -tools-directory=%llvm_obj_root/bin -module-cache-path %t | %FileCheck %s -check-prefix=CHECK-IOSFWD
// RUN: %target-swift-ide-test -print-module -module-to-print=std.string -source-filename=x -enable-experimental-cxx-interop -tools-directory=%llvm_obj_root/bin -module-cache-path %t | %FileCheck %s -check-prefix=CHECK-STRING

// Clang driver on Windows doesn't support -stdlib=libc++
// UNSUPPORTED: OS=windows-msvc

// libstdc++ cannot currently be imported
// UNSUPPORTED: OS=linux-gnu
// UNSUPPORTED: OS=linux-androideabi
// UNSUPPORTED: OS=linux-android
// This test is specific to libc++ and therefore only runs on Darwin platforms.
// REQUIRES: OS=macosx || OS=ios

// REQUIRES: rdar84036022

Expand Down
23 changes: 23 additions & 0 deletions test/Interop/Cxx/stdlib/libstdcxx-module-interface.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// RUN: %target-swift-ide-test -print-module -module-to-print=std -source-filename=x -enable-experimental-cxx-interop -module-cache-path %t | %FileCheck %s -check-prefix=CHECK-STD

// This test is specific to libstdc++ and only runs on platforms where libstdc++ is used.
// REQUIRES: OS=linux-gnu

// CHECK-STD: enum std {
// CHECK-STD: enum __cxx11 {
// CHECK-STD: struct __CxxTemplateInstNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE {
// CHECK-STD: typealias value_type = std.__CxxTemplateInstSt11char_traitsIcE.char_type
// CHECK-STD: }
// CHECK-STD: struct __CxxTemplateInstNSt7__cxx1112basic_stringIwSt11char_traitsIwESaIwEEE {
// CHECK-STD: typealias value_type = std.__CxxTemplateInstSt11char_traitsIwE.char_type
// CHECK-STD: }
// CHECK-STD: }

// CHECK-STD: static func to_string(_ __val: Int32) -> std.string
// CHECK-STD: static func to_wstring(_ __val: Int32) -> std.wstring

// CHECK-STD: typealias size_t = Int

// CHECK-STD: typealias string = std.__cxx11.__CxxTemplateInstNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
// CHECK-STD: typealias wstring = std.__cxx11.__CxxTemplateInstNSt7__cxx1112basic_stringIwSt11char_traitsIwESaIwEEE
// CHECK-STD: }
9 changes: 7 additions & 2 deletions test/Interop/Cxx/stdlib/use-std-string.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@
//
// REQUIRES: executable_test
//
// Enable this everywhere once we have a solution for modularizing libstdc++: rdar://87654514
// REQUIRES: OS=macosx
// Enable this everywhere once we have a solution for modularizing other C++ stdlibs: rdar://87654514
// REQUIRES: OS=macosx || OS=linux-gnu

import StdlibUnittest
import StdString
#if os(Linux)
import std
// FIXME: import std.string once libstdc++ is split into submodules.
#else
import std.string
#endif

var StdStringTestSuite = TestSuite("StdString")

Expand Down