Skip to content

Commit 3bc692b

Browse files
authored
Add Emscripten static library build CppInterOp (#641)
1 parent f3ade2a commit 3bc692b

File tree

7 files changed

+224
-5
lines changed

7 files changed

+224
-5
lines changed

.github/workflows/emscripten.yml

Lines changed: 195 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ jobs:
460460
${{ matrix.cling=='On' && 'cling' || '' }}
461461
key: ${{ env.CLING_HASH }}-${{ runner.os }}-${{ matrix.os }}-clang-${{ matrix.clang-runtime }}.x-emscripten
462462

463-
- name: Emscripten build of CppInterOp on Unix systems
463+
- name: Emscripten build of CppInterOp on Unix systems (shared library)
464464
if: ${{ runner.os != 'windows' }}
465465
shell: bash -l {0}
466466
run: |
@@ -609,6 +609,118 @@ jobs:
609609
emmake make -j ${{ env.ncpus }} install
610610
cd ..
611611
612+
echo "PATH=$PATH" >> $GITHUB_ENV
613+
echo "SYSROOT_PATH=$SYSROOT_PATH" >> $GITHUB_ENV
614+
echo "CB_PYTHON_DIR=$CB_PYTHON_DIR" >> $GITHUB_ENV
615+
echo "CPPINTEROP_DIR=$CPPINTEROP_DIR" >> $GITHUB_ENV
616+
echo "LLVM_BUILD_DIR=$LLVM_BUILD_DIR" >> $GITHUB_ENV
617+
echo "CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH" >> $GITHUB_ENV
618+
echo "PREFIX=$PREFIX" >> $GITHUB_ENV
619+
620+
- name: Emscripten build of CppInterOp on Unix systems (static library)
621+
if: runner.os != 'Windows' && !(startsWith(matrix.os, 'ubuntu') && matrix.clang-runtime == '19' && endsWith(matrix.os, 'arm') )
622+
shell: bash -l {0}
623+
run: |
624+
# FIXME: Static library builds, but tests fail to build on Github runner for Ubuntu arm llvm 19 case
625+
# Disabled build for now
626+
set -e
627+
./emsdk/emsdk activate ${{matrix.emsdk_ver}}
628+
source ./emsdk/emsdk_env.sh
629+
export SYSROOT_PATH=$PWD/emsdk/upstream/emscripten/cache/sysroot
630+
export PREFIX=$MAMBA_ROOT_PREFIX/envs/CppInterOp-wasm
631+
export CMAKE_PREFIX_PATH=$PREFIX
632+
export CMAKE_SYSTEM_PREFIX_PATH=$PREFIX
633+
634+
LLVM_DIR="$(pwd)/llvm-project"
635+
LLVM_BUILD_DIR="$(pwd)/llvm-project/build"
636+
cling_on=$(echo "${{ matrix.cling }}" | tr '[:lower:]' '[:upper:]')
637+
if [[ "${cling_on}" == "ON" ]]; then
638+
CLING_DIR="$(pwd)/cling"
639+
CLING_BUILD_DIR="$(pwd)/cling/build"
640+
CPLUS_INCLUDE_PATH="${CLING_DIR}/tools/cling/include:${CLING_BUILD_DIR}/include:${LLVM_DIR}/llvm/include:${LLVM_DIR}/clang/include:${LLVM_BUILD_DIR}/include:${LLVM_BUILD_DIR}/tools/clang/include:$PWD/include"
641+
else
642+
CPLUS_INCLUDE_PATH="${LLVM_DIR}/llvm/include:${LLVM_DIR}/clang/include:${LLVM_BUILD_DIR}/include:${LLVM_BUILD_DIR}/tools/clang/include:$PWD/include"
643+
fi
644+
645+
# Build CppInterOp next to cling and llvm-project.
646+
mkdir build_static
647+
cd build_static
648+
if [[ "${cling_on}" == "ON" ]]; then
649+
emcmake cmake -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
650+
-DCPPINTEROP_USE_CLING=ON \
651+
-DCPPINTEROP_USE_REPL=OFF \
652+
-DCMAKE_PREFIX_PATH=$PREFIX \
653+
-DCling_DIR=$LLVM_BUILD_DIR/tools/cling \
654+
-DLLVM_DIR=$LLVM_BUILD_DIR/lib/cmake/llvm \
655+
-DLLD_DIR=$LLVM_BUILD_DIR/lib/cmake/lld \
656+
-DClang_DIR=$LLVM_BUILD_DIR/lib/cmake/clang \
657+
-DCODE_COVERAGE=${{ env.CODE_COVERAGE }} \
658+
-DCMAKE_INSTALL_PREFIX=$PREFIX \
659+
-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ON \
660+
-DLLVM_ENABLE_WERROR=On \
661+
-DSYSROOT_PATH=$SYSROOT_PATH \
662+
../
663+
else
664+
emcmake cmake -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
665+
-DCMAKE_PREFIX_PATH=$PREFIX \
666+
-DLLVM_DIR=$LLVM_BUILD_DIR/lib/cmake/llvm \
667+
-DLLD_DIR=$LLVM_BUILD_DIR/lib/cmake/lld \
668+
-DClang_DIR=$LLVM_BUILD_DIR/lib/cmake/clang \
669+
-DCODE_COVERAGE=${{ env.CODE_COVERAGE }} \
670+
-DCMAKE_INSTALL_PREFIX=$PREFIX \
671+
-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ON \
672+
-DLLVM_ENABLE_WERROR=On \
673+
-DSYSROOT_PATH=$SYSROOT_PATH \
674+
../
675+
fi
676+
emmake make -j ${{ env.ncpus }} check-cppinterop
677+
cd ./unittests/CppInterOp/
678+
# Explaination of options for emrun
679+
# --browser (name of browser on path)
680+
# --kill_exit makes it so that when emrun finishes,
681+
# that the headless browser we create is killed along with it
682+
# --timeout 60 is such that emrun is killed after 60 seconds if
683+
# still running. emrun should have finished long before then,
684+
# so if it is still running, something went wrong (such as a test
685+
# which crashed the html file). This will cause the ci to fail,
686+
# as a non 0 value of will be returned.
687+
# In the case of Chrome we have the extra --no-sandbox flag, as on
688+
# Ubuntu Chrome will refuse to run otherwise, as it expects to have
689+
# been installed with admin privileges. This flag allows it to run
690+
# in userspace.
691+
os="${{ matrix.os }}"
692+
if [[ "${os}" == "macos"* ]]; then
693+
# Run tests in browsers
694+
echo "Running CppInterOpTests in Firefox"
695+
emrun --browser="firefox" --kill_exit --timeout 60 --browser-args="--headless" CppInterOpTests.html
696+
echo "Running DynamicLibraryManagerTests in Firefox"
697+
emrun --browser="firefox" --kill_exit --timeout 60 --browser-args="--headless" DynamicLibraryManagerTests.html
698+
echo "Running CppInterOpTests in Google Chrome"
699+
emrun --browser="Google Chrome" --kill_exit --timeout 60 --browser-args="--headless --no-sandbox" CppInterOpTests.html
700+
echo "Running DynamicLibraryManagerTests in Google Chrome"
701+
emrun --browser="Google Chrome" --kill_exit --timeout 60 --browser-args="--headless --no-sandbox" DynamicLibraryManagerTests.html
702+
else
703+
export ARCHITECHURE=$(uname -m)
704+
if [[ "$ARCHITECHURE" != "aarch64" ]]; then
705+
# Run tests in browsers
706+
echo "Running CppInterOpTests in Firefox"
707+
emrun --browser="firefox" --kill_exit --timeout 60 --browser-args="--headless" CppInterOpTests.html
708+
echo "Running DynamicLibraryManagerTests in Firefox"
709+
emrun --browser="firefox" --kill_exit --timeout 60 --browser-args="--headless" DynamicLibraryManagerTests.html
710+
echo "Running CppInterOpTests in Google Chrome"
711+
emrun --browser="google-chrome" --kill_exit --timeout 60 --browser-args="--headless --no-sandbox" CppInterOpTests.html
712+
echo "Running DynamicLibraryManagerTests in Google Chrome"
713+
emrun --browser="google-chrome" --kill_exit --timeout 60 --browser-args="--headless --no-sandbox" DynamicLibraryManagerTests.html
714+
else
715+
# Run tests in browsers
716+
echo "Running CppInterOpTests in Firefox"
717+
emrun --browser="firefox" --kill_exit --timeout 60 --browser-args="--headless" CppInterOpTests.html
718+
echo "Running DynamicLibraryManagerTests in Firefox"
719+
emrun --browser="firefox" --kill_exit --timeout 60 --browser-args="--headless" DynamicLibraryManagerTests.html
720+
fi
721+
fi
722+
cd ../../..
723+
612724
echo "SYSROOT_PATH=$SYSROOT_PATH" >> $GITHUB_ENV
613725
echo "CB_PYTHON_DIR=$CB_PYTHON_DIR" >> $GITHUB_ENV
614726
echo "CPPINTEROP_DIR=$CPPINTEROP_DIR" >> $GITHUB_ENV
@@ -622,7 +734,7 @@ jobs:
622734
run: |
623735
micromamba shell hook -s cmd.exe --root-prefix C:\Users\runneradmin\micromamba-root
624736
625-
- name: Build and Test/Install CppInterOp on Windows systems
737+
- name: Build and Test/Install CppInterOp on Windows systems (shared library)
626738
continue-on-error: true
627739
if: ${{ runner.os == 'windows' }}
628740
shell: powershell
@@ -707,7 +819,88 @@ jobs:
707819
}
708820
emmake make -j ${{ env.ncpus }} check-cppinterop
709821
emmake make -j ${{ env.ncpus }} install
822+
823+
- name: Build and Test/Install CppInterOp on Windows systems (static library)
824+
continue-on-error: true
825+
if: ${{ runner.os == 'windows' }}
826+
shell: powershell
827+
run: |
828+
$ErrorActionPreference = "Stop"
829+
.\emsdk\emsdk activate ${{matrix.emsdk_ver}}
830+
.\emsdk\emsdk_env.ps1
831+
$env:PWD_DIR= $PWD.Path
832+
$env:SYSROOT_PATH="$env:EMSDK/upstream/emscripten/cache/sysroot"
833+
$env:PREFIX="%CONDA_PREFIX%/envs/CppInterOp-wasm"
834+
$env:CMAKE_PREFIX_PATH=$env:PREFIX
835+
$env:CMAKE_SYSTEM_PREFIX_PATH=$env:PREFIX
710836
837+
$env:LLVM_DIR="$env:PWD_DIR\llvm-project"
838+
echo "LLVM_DIR=$env:LLVM_DIR"
839+
echo "LLVM_DIR=$env:LLVM_DIR" >> $env:GITHUB_ENV
840+
841+
$env:LLVM_BUILD_DIR="$env:PWD_DIR\llvm-project\build"
842+
echo "LLVM_BUILD_DIR=$env:LLVM_BUILD_DIR"
843+
echo "LLVM_BUILD_DIR=$env:LLVM_BUILD_DIR" >> $env:GITHUB_ENV
844+
845+
if ( "${{ matrix.cling }}" -imatch "On" )
846+
{
847+
$env:CLING_DIR="$env:PWD_DIR\cling"
848+
echo "CLING_DIR=$env:CLING_DIR"
849+
echo "CLING_DIR=$env:CLING_DIR" >> $env:GITHUB_ENV
850+
851+
$env:CLING_BUILD_DIR="$env:PWD_DIR\cling\build"
852+
echo "CLING_BUILD_DIR=$env:CLING_BUILD_DIR"
853+
echo "CLING_BUILD_DIR=$env:CLING_BUILD_DIR" >> $env:GITHUB_ENV
854+
855+
$env:CPLUS_INCLUDE_PATH="$env:CLING_DIR\tools\cling\include;$env:CLING_BUILD_DIR\include;$env:LLVM_DIR\llvm\include;$env:LLVM_DIR\clang\include;$env:LLVM_BUILD_DIR\include;$env:LLVM_BUILD_DIR\tools\clang\include;$env:PWD_DIR\include;"
856+
echo "CPLUS_INCLUDE_PATH=$env:CPLUS_INCLUDE_PATH"
857+
echo "CPLUS_INCLUDE_PATH=$env:CPLUS_INCLUDE_PATH" >> $env:GITHUB_ENV
858+
}
859+
else
860+
{
861+
$env:CPLUS_INCLUDE_PATH="$env:LLVM_DIR\llvm\include;$env:LLVM_DIR\clang\include;$env:LLVM_BUILD_DIR\include;$env:LLVM_BUILD_DIR\tools\clang\include;$env:PWD_DIR\include;"
862+
echo "CPLUS_INCLUDE_PATH=$env:CPLUS_INCLUDE_PATH"
863+
echo "CPLUS_INCLUDE_PATH=$env:CPLUS_INCLUDE_PATH" >> $env:GITHUB_ENV
864+
}
865+
866+
# Build CppInterOp next to cling and llvm-project.
867+
mkdir build_static
868+
cd build_static
869+
$env:CPPINTEROP_BUILD_DIR="$env:PWD_DIR"
870+
echo "CPPINTEROP_BUILD_DIR=$env:CPPINTEROP_BUILD_DIR"
871+
echo "CPPINTEROP_BUILD_DIR=$env:CPPINTEROP_BUILD_DIR" >> $env:GITHUB_ENV
872+
if ( "${{ matrix.cling }}" -imatch "On" )
873+
{
874+
emcmake cmake -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} `
875+
-DCPPINTEROP_USE_CLING=ON `
876+
-DCPPINTEROP_USE_REPL=OFF `
877+
-DCMAKE_PREFIX_PATH="$env:PREFIX" `
878+
-DCling_DIR="$env:LLVM_BUILD_DIR\tools\cling" `
879+
-DLLVM_DIR="$env:LLVM_BUILD_DIR\lib\cmake\llvm" `
880+
-DLLD_DIR="$env:LLVM_BUILD_DIR\lib\cmake\lld" `
881+
-DClang_DIR="$env:LLVM_BUILD_DIR\lib\cmake\clang" `
882+
-DCODE_COVERAGE=${{ env.CODE_COVERAGE }} `
883+
-DCMAKE_INSTALL_PREFIX="$env:PREFIX" `
884+
-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ON `
885+
-DLLVM_ENABLE_WERROR=On `
886+
-DSYSROOT_PATH="$env:SYSROOT_PATH" `
887+
..\
888+
}
889+
else
890+
{
891+
emcmake cmake -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} `
892+
-DCMAKE_PREFIX_PATH="$env:PREFIX" `
893+
-DLLVM_DIR="$env:LLVM_BUILD_DIR\lib\cmake\llvm" `
894+
-DLLD_DIR="$env:LLVM_BUILD_DIR\lib\cmake\lld" `
895+
-DClang_DIR="$env:LLVM_BUILD_DIR\lib\cmake\clang" `
896+
-DCODE_COVERAGE=${{ env.CODE_COVERAGE }} `
897+
-DCMAKE_INSTALL_PREFIX="$env:PREFIX" `
898+
-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ON `
899+
-DLLVM_ENABLE_WERROR=On `
900+
-DSYSROOT_PATH="$env:SYSROOT_PATH" `
901+
..\
902+
}
903+
emmake make -j ${{ env.ncpus }} check-cppinterop
711904
712905
- name: Build xeus-cpp
713906
if: ${{ runner.os != 'windows' }}

Emscripten-build-instructions.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ $env:CMAKE_SYSTEM_PREFIX_PATH=$env:PREFIX
173173
```
174174

175175
on Windows. Now to build and test your Emscripten build of CppInterOp using node on Linux and osx execute the following
176+
(BUILD_SHARED_LIBS=ON is only needed if building xeus-cpp, as CppInterOp can be built as an Emscripten static library)
176177

177178
```bash
178179
mkdir build
@@ -190,6 +191,7 @@ emmake make -j $(nproc --all) check-cppinterop
190191
```
191192

192193
To build and test your Emscripten build of CppInterOp on using node Windows execute the following
194+
(BUILD_SHARED_LIBS=ON is only needed if building xeus-cpp, as CppInterOp can be built as an Emscripten static library)
193195

194196
```powershell
195197
emcmake cmake -DCMAKE_BUILD_TYPE=Release `

docs/Emscripten-build-instructions.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ and
197197
$env:CMAKE_SYSTEM_PREFIX_PATH=$env:PREFIX
198198
199199
on Windows. Now to build and test your Emscripten build of CppInterOp on Linux and osx execute the following
200+
(BUILD_SHARED_LIBS=ON is only needed if building xeus-cpp, as CppInterOp can be built as an Emscripten static library)
200201

201202
.. code:: bash
202203
@@ -214,6 +215,7 @@ on Windows. Now to build and test your Emscripten build of CppInterOp on Linux a
214215
emmake make -j $(nproc --all) check-cppinterop
215216
216217
To build and test your Emscripten build of CppInterOp on Windows execute the following
218+
(BUILD_SHARED_LIBS=ON is only needed if building xeus-cpp, as CppInterOp can be built as an Emscripten static library)
217219

218220
.. code:: powershell
219221

lib/CppInterOp/CMakeLists.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ endif()
114114

115115

116116
if(EMSCRIPTEN)
117+
if(BUILD_SHARED_LIBS)
117118
# FIXME: When dynamically linking the Emscripten shared library to the
118119
# unit tests main_module you get errors due to undefined symbols. The reading of the file
119120
# below into a SYMBOLS_LIST variable is a temporary workaround that exports the undefined
@@ -131,8 +132,13 @@ if(EMSCRIPTEN)
131132
PRIVATE "SHELL: -s SIDE_MODULE=1"
132133
PRIVATE "SHELL: ${SYMBOLS_LIST}"
133134
)
135+
else()
136+
target_link_options(clangCppInterOp
137+
PRIVATE "SHELL: -s WASM_BIGINT"
138+
)
139+
endif()
134140
if (CPPINTEROP_ENABLE_TESTING)
135-
# When compiling Emscripten tests the shared library it links to is expected to be in the same folder as the compiled Javascript
141+
# When compiling Emscripten tests the CppInterOp library it links to is expected to be in the same folder as the compiled Javascript
136142
add_custom_command(TARGET clangCppInterOp POST_BUILD
137143
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:clangCppInterOp> ${CMAKE_BINARY_DIR}/unittests/CppInterOp/
138144
)

unittests/CppInterOp/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,16 @@ if(EMSCRIPTEN)
112112
)
113113
endif()
114114

115+
if (EMSCRIPTEN)
116+
if (BUILD_SHARED_LIBS)
117+
target_compile_definitions(CppInterOpTests PRIVATE "EMSCRIPTEN_SHARED_LIBRARY")
118+
target_compile_definitions(DynamicLibraryManagerTests PRIVATE "EMSCRIPTEN_SHARED_LIBRARY")
119+
else()
120+
target_compile_definitions(CppInterOpTests PRIVATE "EMSCRIPTEN_STATIC_LIBRARY")
121+
target_compile_definitions(DynamicLibraryManagerTests PRIVATE "EMSCRIPTEN_STATIC_LIBRARY")
122+
endif()
123+
endif()
124+
115125
set_output_directory(DynamicLibraryManagerTests
116126
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${EXTRA_PATH_TEST_BINARIES}
117127
LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${EXTRA_PATH_TEST_BINARIES}

unittests/CppInterOp/FunctionReflectionTest.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2485,8 +2485,8 @@ TEST(FunctionReflectionTest, FailingTest1) {
24852485
#ifdef _WIN32
24862486
GTEST_SKIP() << "Disabled on Windows. Needs fixing.";
24872487
#endif
2488-
#ifdef EMSCRIPTEN
2489-
GTEST_SKIP() << "Test fails for Emscipten builds";
2488+
#ifdef EMSCRIPTEN_SHARED_LIBRARY
2489+
GTEST_SKIP() << "Test fails for Emscipten shared library builds";
24902490
#endif
24912491
Cpp::CreateInterpreter();
24922492
EXPECT_FALSE(Cpp::Declare(R"(

unittests/CppInterOp/InterpreterTest.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ TEST(InterpreterTest, DeleteInterpreter) {
9999
}
100100

101101
TEST(InterpreterTest, ActivateInterpreter) {
102+
#ifdef EMSCRIPTEN_STATIC_LIBRARY
103+
GTEST_SKIP() << "Test fails for Emscipten static library build";
104+
#endif
102105
EXPECT_FALSE(Cpp::ActivateInterpreter(nullptr));
103106
auto* Cpp14 = Cpp::CreateInterpreter({"-std=c++14"});
104107
auto* Cpp17 = Cpp::CreateInterpreter({"-std=c++17"});
@@ -122,6 +125,9 @@ TEST(InterpreterTest, ActivateInterpreter) {
122125
}
123126

124127
TEST(InterpreterTest, Process) {
128+
#ifdef EMSCRIPTEN_STATIC_LIBRARY
129+
GTEST_SKIP() << "Test fails for Emscipten static library build";
130+
#endif
125131
#ifdef _WIN32
126132
GTEST_SKIP() << "Disabled on Windows. Needs fixing.";
127133
#endif

0 commit comments

Comments
 (0)