Skip to content

Commit

Permalink
modules in shared libraries
Browse files Browse the repository at this point in the history
1. [GCC] initializer for module is hidden with -fvisibility=hidden
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105397

2. [Clang] initializer for module is not dllexported when targeting MinGW
mstorsjo/llvm-mingw#421

3. [Clang] not strong ownership model when targeting MSVC ABI
llvm/llvm-project#89781

4. [Clang] module variables are not dllimported
llvm/llvm-project#87887

5. [DLL] module functions are not dllimported causing indirect function call
https://stackoverflow.com/a/74444920
https://developercommunity.visualstudio.com/t/10202062
https://gitlab.kitware.com/cmake/cmake/-/issues/25539
  • Loading branch information
huangqinjin committed May 4, 2024
1 parent 648f8d5 commit b946b8d
Show file tree
Hide file tree
Showing 12 changed files with 222 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,10 @@ CMakeUserPresets.json
*.pcm
*.gcm
*.exe
*.exp
*.lib
*.dll
*.pdb
*.a
*.so
*.dylib
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ add_subdirectory(module-partition)
add_subdirectory(module-impl)
# add_subdirectory(header-unit)
add_subdirectory(import-std)
add_subdirectory(shared-lib)
48 changes: 48 additions & 0 deletions shared-lib/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
cmake_minimum_required(VERSION 3.28)
project(shared-lib)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_BUILD_RPATH_USE_ORIGIN ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_VISIBILITY_INLINES_HIDDEN ON)
set(CMAKE_C_VISIBILITY_PRESET hidden)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)

# https://gitlab.kitware.com/cmake/cmake/-/issues/25875
if(CMAKE_VISIBILITY_INLINES_HIDDEN AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND WIN32)
if(CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
add_compile_options(/Zc:dllexportInlines-)
else()
add_compile_options(-Xclang=-fno-dllexport-inlines)
endif()
endif()

add_library(hello SHARED)
target_sources(hello
PRIVATE
impl.cpp
PUBLIC FILE_SET HEADERS FILES
hello.hpp
PUBLIC FILE_SET CXX_MODULES FILES
hello.ixx
)

# https://github.com/mstorsjo/llvm-mingw/issues/421
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND MINGW)
# -fms-extensions is disabled by default for MinGW
target_link_options(hello PRIVATE LINKER:-Xlink=-export:_ZGIW5hello)
endif()

# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105397
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
target_link_options(hello INTERFACE LINKER:--wrap=_ZGIW5hello)
endif()

add_executable(${PROJECT_NAME})
target_sources(${PROJECT_NAME}
PRIVATE
main.cpp
)
target_link_libraries(${PROJECT_NAME} PUBLIC hello)

add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME})
12 changes: 12 additions & 0 deletions shared-lib/Makefile.clang
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
hello.exe: main.cpp libhello.so hello.pcm
clang++ -std=c++20 -g -fprebuilt-module-path=. main.cpp -o hello.exe libhello.so -Wl,-rpath,.

libhello.so hello.pcm: hello.ixx hello.hpp impl.cpp
clang++ -std=c++20 -g -fprebuilt-module-path=. -fmodule-output -shared -fPIC \
-fvisibility=hidden -fvisibility-inlines-hidden \
-x c++-module hello.ixx -x c++ impl.cpp -o libhello.so

clean:
-rm *.pcm *.o *.exe *.so
-del *.pcm *.o *.exe *.so

15 changes: 15 additions & 0 deletions shared-lib/Makefile.clang-mingw
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
hello.exe: main.cpp hello.dll hello.pcm
$(PREFIX)clang++ -fms-extensions -std=c++20 -fprebuilt-module-path=. \
-g -gcodeview -Wl,--pdb=hello.exe.pdb \
main.cpp -o hello.exe -L. -lhello

hello.dll hello.pcm: hello.ixx hello.hpp impl.cpp
$(PREFIX)clang++ -fms-extensions -std=c++20 -fprebuilt-module-path=. -fmodule-output -shared \
-fvisibility=hidden -fvisibility-inlines-hidden \
-g -gcodeview -Wl,--pdb=hello.dll.pdb \
-x c++-module hello.ixx -x c++ impl.cpp -o hello.dll

clean:
-rm *.pcm *.o *.obj *.exe *.exp *.lib *.dll *.pdb
-del *.pcm *.o *.obj *.exe *.exp *.lib *.dll *.pdb

16 changes: 16 additions & 0 deletions shared-lib/Makefile.clang-win32
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
hello.exe: main.cpp hello.lib hello.pcm
clang++ -std=c++20 -fprebuilt-module-path=. \
-Xclang -fno-dllexport-inlines \
-g -gcodeview -Wl,/PDB:hello.exe.pdb -Wl,/INCREMENTAL:NO \
main.cpp -o hello.exe hello.lib -Wl,/NOIMPLIB

hello.dll hello.lib hello.pcm: hello.ixx hello.hpp impl.cpp
clang++ -std=c++20 -fprebuilt-module-path=. -fmodule-output -shared \
-Xclang -fno-dllexport-inlines \
-g -gcodeview -Wl,/PDB:hello.dll.pdb -Wl,/INCREMENTAL:NO \
-x c++-module hello.ixx -x c++ impl.cpp -o hello.dll

clean:
-rm *.pcm *.o *.obj *.exe *.exp *.lib *.dll *.pdb
-del *.pcm *.o *.obj *.exe *.exp *.lib *.dll *.pdb

11 changes: 11 additions & 0 deletions shared-lib/Makefile.gcc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
hello.exe: main.cpp libhello.so gcm.cache/hello.gcm
g++ -std=c++20 -fmodules-ts -g main.cpp -o hello.exe libhello.so -Wl,-rpath,. -Wl,--wrap=_ZGIW5hello

libhello.so gcm.cache/hello.gcm: hello.ixx hello.hpp impl.cpp
g++ -std=c++20 -fmodules-ts -g -shared -fPIC \
-fvisibility=hidden -fvisibility-inlines-hidden \
-x c++ hello.ixx impl.cpp -o libhello.so

clean:
rm -rf *.gcm gcm.* *.o *.exe *.so

10 changes: 10 additions & 0 deletions shared-lib/Makefile.msvc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
hello.exe: main.cpp hello.lib hello.ifc
cl /nologo /EHsc /std:c++20 main.cpp hello.lib /Fe:hello /Zi /link /PDB:hello.exe.pdb /INCREMENTAL:NO /NOIMPLIB /NOEXP

hello.dll hello.lib hello.ifc: hello.ixx hello.hpp impl.cpp
cl /nologo /EHsc /std:c++20 /LD hello.ixx impl.cpp /Zi /link /PDB:hello.dll.pdb

clean:
-del *.ifc *.obj *.exe *.exp *.lib *.dll *.pdb
-rm *.ifc *.obj *.exe *.exp *.lib *.dll *.pdb

19 changes: 19 additions & 0 deletions shared-lib/hello.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once

#if defined(_WIN32) || defined(__CYGWIN__)
# define EXPORT __declspec(dllexport)
# define IMPORT __declspec(dllimport)
#else
# define EXPORT __attribute__((visibility("default")))
# define IMPORT __attribute__((visibility("default")))
#endif

#if defined(IMPL)
#include <iostream>
extern "C++" EXPORT void is_direct_call_to_gmf(void(*f)())
{
std::cout << __func__ << "? " << (f == (void(*)())&is_direct_call_to_gmf ? "Yes" : "No") << std::endl;
}
#elif defined(DECL)
IMPORT void is_direct_call_to_gmf(void(*f)());
#endif
36 changes: 36 additions & 0 deletions shared-lib/hello.ixx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
module;

#include <source_location>
//#define IMPL
#include "hello.hpp"

export module hello;

// https://github.com/mstorsjo/llvm-mingw/issues/421
#if defined(__clang__) && defined(__MINGW32__)
# pragma comment(linker, "-export:_ZGIW5hello") //-fms-extensions
#endif

// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105397
#if defined(__GNUC__) && !defined(__clang__)
extern "C" EXPORT void __wrap__ZGIW5hello() __attribute__((alias("_ZGIW5hello"))); //-Wl,--wrap=_ZGIW5hello
#endif

// https://developercommunity.visualstudio.com/t/10651933
export EXPORT auto gploc = new auto([] { return std::source_location::current(); }());

export EXPORT void hello(const std::source_location* ploc = nullptr);
export EXPORT void is_direct_call_to_hello(void(*f)(const std::source_location*));

export class EXPORT Hello
{
public:
auto hello()
{
return inline_hello();
}

inline void inline_hello()
{
}
};
22 changes: 22 additions & 0 deletions shared-lib/impl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module;

#include <iostream>
#include <source_location>

#define IMPL
#include "hello.hpp"

module hello;

void hello(const std::source_location* ploc)
{
// https://developercommunity.visualstudio.com/t/10651933
const auto& loc = ploc ? *ploc : [] { return std::source_location::current(); }();
std::cout << loc.file_name() << '(' << loc.line() << ')' << ':' << ' '
<< "Hello, World!" << std::endl;
}

void is_direct_call_to_hello(void(*f)(const std::source_location*))
{
std::cout << __func__ << "? " << (f == &hello ? "Yes" : "No") << std::endl;
}
25 changes: 25 additions & 0 deletions shared-lib/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#define DECL
#include "hello.hpp"

import hello;

// https://github.com/llvm/llvm-project/issues/87887
#if defined(__clang__) && defined(_WIN32) && !defined(__MINGW32__)
extern "C" decltype(gploc)& __imp_gploc;
// https://github.com/llvm/llvm-project/issues/89781
// #pragma comment(linker, "/ALTERNATENAME:__imp_gploc=__imp_?gploc@@3PEAUsource_location@std@@EA::<!hello>")
#pragma comment(linker, "/ALTERNATENAME:__imp_gploc=__imp_?gploc@@3PEAUsource_location@std@@EA")
#define gploc __imp_gploc
#endif

int main()
{
hello();
hello(gploc);

Hello{}.hello();
Hello{}.inline_hello();

is_direct_call_to_hello(&hello);
is_direct_call_to_gmf((void(*)())&is_direct_call_to_gmf);
}

0 comments on commit b946b8d

Please sign in to comment.