From a6870c9679a929d45e9c1c299959ce55385e22b2 Mon Sep 17 00:00:00 2001 From: Philippe Gras Date: Thu, 6 Feb 2025 15:38:51 +0100 Subject: [PATCH] Add an option to build clang from source code and more. - new -DBUILD_LLVM cmake option to download and build LLVM and Clang when building wrapit - use above option for macOS CI as clang 13 is no more available from homebrew - remove test with julia-head, because it often needs a libcxxwrap_julia_jll that is not registered. - remove from test/runtest.jl use of --fresh cmake option, not supported in older cmake releases and improved cleanup before compilation by deleting the full build directory if it already exists. --- .github/workflows/test-linux.yml | 6 +- .github/workflows/test-macos.yml | 33 ++-- CMakeLists.txt | 255 ++++++++++++++++++++----------- test/runtests.jl | 11 +- 4 files changed, 196 insertions(+), 109 deletions(-) diff --git a/.github/workflows/test-linux.yml b/.github/workflows/test-linux.yml index 8e6da72..7185d71 100644 --- a/.github/workflows/test-linux.yml +++ b/.github/workflows/test-linux.yml @@ -18,9 +18,9 @@ jobs: matrix: version: - '1.10' - - 'nightly' os: - - ubuntu-latest +# - ubuntu-latest + - ubuntu-22.04 # - macOS-latest arch: - x64 @@ -28,7 +28,7 @@ jobs: - uses: actions/checkout@v3 with: fetch-depth: 0 - - name: Install liclang + - name: Install libclang run: | if [ "$RUNNER_OS" = Linux ]; then sudo apt-get install clang-13 libclang-13-dev diff --git a/.github/workflows/test-macos.yml b/.github/workflows/test-macos.yml index 62525fa..485cf05 100644 --- a/.github/workflows/test-macos.yml +++ b/.github/workflows/test-macos.yml @@ -18,22 +18,29 @@ jobs: matrix: version: - '1.10' - - 'nightly' os: # - ubuntu-latest - - macOS-latest +# - macOS-latest + - macos-13 arch: - x64 steps: - uses: actions/checkout@v3 with: fetch-depth: 0 - - name: Install liclang + - name: Install libclang run: | if [ "$RUNNER_OS" = Linux ]; then sudo apt-get install clang-13 libclang-13-dev - else #MacOS - brew install llvm@13 + #else #MacOS + # #brew install llvm@13 #llvm@13 no more supported by brew + # wget "https://github.com/llvm/llvm-project/archive/refs/tags/llvmorg-13.0.1.tar.gz" + # tar xzf llvmorg-13.0.1.tar.gz + # rm llvmorg-13.0.1.tar.gz + # export CMAKE_INSTALL_MODE=SYMLINK #use symlinks to reduce disk space usage + # cmake -S llvm-project-llvmorg-13.0.1/llvm -B llvm-build -DCMAKE_INSTALL_PREFIX=`pwd`/clang-13 -DLLVM_ENABLE_PROJECTS="clang" -DBUILD_SHARED_LIBS=on -DLLVM_BUILD_LLVM_DYLIB=on -DCMAKE_BUILD_TYPE=Release + # cmake --build llvm-build --verbose -j `sysctl -n hw.logicalcpu` + # cmake --install llvm-build fi - uses: julia-actions/setup-julia@latest with: @@ -49,13 +56,13 @@ jobs: rm -f /opt/hostedtoolcache/julia/1.6*/x64/lib/julia/libstdc++.so.6 fi if [ "$RUNNER_OS" = Linux ]; then - cmake -DClang_DIR=/usr/lib/llvm-13/lib/cmake/clang -B build -S . - else #MacOS - #cmake -DClang_DIR=/usr/local/Cellar/llvm@13/13.0.1_2/lib/cmake/clang/ -B build -S . - echo ls /opt/homebrew/opt/llvm@13/lib/cmake/clang - ls /opt/homebrew/opt/llvm@13/lib/cmake/clang - cmake -DClang_DIR=/opt/homebrew/opt/llvm@13/lib/cmake/clang -B build -S . + cmake -DClang_DIR=/usr/lib/llvm-13/lib/cmake/clang -DCMAKE_INSTALL_PREFIX="$PWD" -B build -S . + cmake --build build --verbose -j `nproc` + else + cmake -DBUILD_LLVM=ON -DCMAKE_INSTALL_PREFIX="$PWD" -B build -S . + cmake --build build --verbose -j `sysctl -n hw.logicalcpu` fi - cmake --build build --verbose -j `nproc` - PATH="`pwd`/build:$PATH" + cmake --install build + PATH="$PATH:$PWD/bin" + export SDKROOT="$(xcrun --sdk macosx --show-sdk-path)" cd test && ./runtests.jl diff --git a/CMakeLists.txt b/CMakeLists.txt index 644df79..b620a1d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,125 +17,204 @@ FetchContent_Declare( GIT_REPOSITORY https://github.com/jarro2783/cxxopts.git GIT_TAG v3.0.0 ) + +if(BUILD_LLVM) #in this mode llvm and clang codes are downloaded + FetchContent_Declare(llvm + SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/llvm + DOWNLOAD_EXTRACT_TIMESTAMP TRUE + URL https://github.com/llvm/llvm-project/releases/download/llvmorg-13.0.1/llvm-13.0.1.src.tar.xz + ) + FetchContent_GetProperties(llvm) + if(NOT llvm_POPULATED) + FetchContent_Populate(llvm) + endif() + + FetchContent_Declare(clang + SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/llvm/tools/clang + DOWNLOAD_EXTRACT_TIMESTAMP TRUE + URL https://github.com/llvm/llvm-project/releases/download/llvmorg-13.0.1/clang-13.0.1.src.tar.xz + ) + FetchContent_GetProperties(clang) + if(NOT clang_POPULATED) + FetchContent_Populate(clang) + endif() +endif() + FetchContent_MakeAvailable(cxxopts) -# CLANG_JLL is used by Binary Builder -# For building the package stand-alone it is not used -if (NOT CLANG_JLL) +project(MyProject) + +# Option to enable LLVM/Clang download and build +option(BUILD_LLVM "Download and build LLVM/Clang" OFF) + +if(BUILD_LLVM) + + function(add_llvm) + set(CMAKE_BUILD_TYPE Release) #applies only for LLVM as defined in the function + set(LLVM_BUILD_LLVM_DYLIB ON) + set(LLVM_BUILD_TOOLS OFF) + + set(LLVM_TARGETS_TO_BUILD host) + + # Define a couple of LLVM cache variables of LLVM before adding the subdirectory + # in order to choose the default values. + set(LLVM_TARGETS_TO_BUILD ${LLVM_TARGETS_TO_BUILD_} CACHE STRING "Semicolon-separated list of experimental targets to build.") + + set(CLANG_RESOURCE_DIR ${CMAKE_INSTALL_PREFIX}/lib/clang/13.0.1 CACHE STRING + "Clang resource directory as returned by clang -print-resource-dir") + + add_subdirectory(${llvm_SOURCE_DIR} ${llvm_BINARY_DIR}) + endfunction() + + add_llvm() + +# include_directories(${llvm_SOURCE_DIR}/include +# ${clang_SOURCE_DIR}/include +# ${llvm_BINARY_DIR}/tools/clang/include +# ${llvm_BINARY_DIR}/include) + +elseif (NOT CLANG_JLL) - find_package(Clang REQUIRED CONFIG) - find_package(LLVM REQUIRED CONFIG) - include_directories(${CLANG_INCLUDE_DIRS}) + find_package(Clang REQUIRED CONFIG) + find_package(LLVM REQUIRED CONFIG) + include_directories(${CLANG_INCLUDE_DIRS}) - execute_process(COMMAND "${LLVM_TOOLS_BINARY_DIR}/clang" -print-resource-dir + execute_process(COMMAND "${LLVM_TOOLS_BINARY_DIR}/clang" -print-resource-dir OUTPUT_VARIABLE CLANG_RESOURCE_DIR_DISCOVERED_PATH OUTPUT_STRIP_TRAILING_WHITESPACE) - + set(CLANG_RESOURCE_DIR "${CLANG_RESOURCE_DIR_DISCOVERED_PATH}" CACHE FILEPATH "Clang resource directory as returned by clang -print-resource-dir") if("${CLANG_RESOURCE_DIR}" STREQUAL "") - message(FATAL_ERROR "CLANG_RESOURCE_DIR needs to be set to the Clang resource directory (see clang -print-resource-directory). This path is used at runtime by the wrapit executable.") + message(FATAL_ERROR "CLANG_RESOURCE_DIR needs to be set to the Clang resource directory (see clang -print-resource-directory). This path is used at runtime by the wrapit executable.") else() - if(NOT IS_DIRECTORY "${CLANG_RESOURCE_DIR}") - message(WARNING "CLANG_RESOURCE_DIR value, " "${CLANG_RESOURCE_DIR}" ", does not point to an existing directory.") - endif() + if(NOT IS_DIRECTORY "${CLANG_RESOURCE_DIR}") + message(WARNING "CLANG_RESOURCE_DIR value, " "${CLANG_RESOURCE_DIR}" ", does not point to an existing directory.") + endif() endif() else() # Using Clang_jll - # find_package(Clang) leads to errors with Clang_jll - # due to inconsitency in the lists of expected and installed files - - set(CLANG_PREFIX "" CACHE FILEPATH "Root path of libclang that contains lib/libclang.so.") - if("${CLANG_PREFIX}" STREQUAL "") - find_library(LIBCLANG_PATH_ clang REQUIRED NOCACHE) - get_filename_component(CLANG_PREFIX "${LIBCLANG_PATH_}" DIRECTORY) - get_filename_component(CLANG_PREFIX "${CLANG_PREFIX}" DIRECTORY) - unset(LIBCLANG_PATH_) - message(STATUS "CLANG_PREFIX: ${CLANG_PREFIX}") - endif() - include_directories("${CLANG_PREFIX}/include") - - set(CLANG_RESOURCE_DIR "" CACHE STRING - "Clang resource directory as returned by clang -print-resource-dir") - if("${CLANG_RESOURCE_DIR}" STREQUAL "") - message("Searching clang resource directory in " "${CLANG_PREFIX}/lib/clang") - file(GLOB CLANG_RESOURCE_DIR_ "${CLANG_PREFIX}/lib/clang/*/include/stddef.h") - if("${CLANG_RESOURCE_DIR_}" STREQUAL "") - message(FATAL_ERROR "Failed to find Clang resource directory") - else() - list(GET CLANG_RESOURCE_DIR_ 0 CLANG_RESOURCE_DIR) - unset(CLANG_RESOURCE_DIR_) - get_filename_component(CLANG_RESOURCE_DIR "${CLANG_RESOURCE_DIR}" DIRECTORY) - get_filename_component(CLANG_RESOURCE_DIR "${CLANG_RESOURCE_DIR}" DIRECTORY) - message(STATUS "CLANG_RESOURCE_DIR: ${CLANG_RESOURCE_DIR}") - endif() - endif() - - set(SHARED_LIBS libclang clang-cpp LLVM) - foreach(shared_lib IN LISTS SHARED_LIBS) - add_library(${shared_lib} SHARED IMPORTED) - set(lib_path "${CLANG_PREFIX}/lib/lib${shared_lib}${CMAKE_SHARED_LIBRARY_SUFFIX}") - string(REPLACE liblib lib lib_path ${lib_path}) - set_property(TARGET ${shared_lib} PROPERTY - IMPORTED_LOCATION ${lib_path}) - endforeach() - - #To prevent 'undefined symbol: _ZN4llvm23EnableABIBreakingChecksE' error: - add_compile_definitions(LLVM_DISABLE_ABI_BREAKING_CHECKS_ENFORCING) - - if(NOT ($ENV{target} MATCHES "darwin")) - execute_process(COMMAND /bin/sh -c "nm -D -C ${CLANG_PREFIX}/lib/libclang.so | grep -q abi:cxx11" RESULT_VARIABLE rc) - if(NOT (rc EQUAL 0)) #libclang.so compiled with cxx03 ABI - add_compile_options(-D_GLIBCXX_USE_CXX11_ABI=0) - endif() - endif() + # find_package(Clang) leads to errors with Clang_jll + # due to inconsitency in the lists of expected and installed files + + set(CLANG_PREFIX "" CACHE FILEPATH "Root path of libclang that contains lib/libclang.so.") + if("${CLANG_PREFIX}" STREQUAL "") + find_library(LIBCLANG_PATH_ clang REQUIRED NOCACHE) + get_filename_component(CLANG_PREFIX "${LIBCLANG_PATH_}" DIRECTORY) + get_filename_component(CLANG_PREFIX "${CLANG_PREFIX}" DIRECTORY) + unset(LIBCLANG_PATH_) + message(STATUS "CLANG_PREFIX: ${CLANG_PREFIX}") + endif() + include_directories("${CLANG_PREFIX}/include") + + set(CLANG_RESOURCE_DIR "" CACHE STRING + "Clang resource directory as returned by clang -print-resource-dir") + if("${CLANG_RESOURCE_DIR}" STREQUAL "") + message("Searching clang resource directory in " "${CLANG_PREFIX}/lib/clang") + file(GLOB CLANG_RESOURCE_DIR_ "${CLANG_PREFIX}/lib/clang/*/include/stddef.h") + if("${CLANG_RESOURCE_DIR_}" STREQUAL "") + message(FATAL_ERROR "Failed to find Clang resource directory") + else() + list(GET CLANG_RESOURCE_DIR_ 0 CLANG_RESOURCE_DIR) + unset(CLANG_RESOURCE_DIR_) + get_filename_component(CLANG_RESOURCE_DIR "${CLANG_RESOURCE_DIR}" DIRECTORY) + get_filename_component(CLANG_RESOURCE_DIR "${CLANG_RESOURCE_DIR}" DIRECTORY) + message(STATUS "CLANG_RESOURCE_DIR: ${CLANG_RESOURCE_DIR}") + endif() + endif() + + set(SHARED_LIBS libclang clang-cpp LLVM) + foreach(shared_lib IN LISTS SHARED_LIBS) + set(lib_path "${CLANG_PREFIX}/lib/lib${shared_lib}${CMAKE_SHARED_LIBRARY_SUFFIX}") + string(REPLACE liblib lib lib_path ${lib_path}) + if(EXISTS "${lib_path}") + add_library(${shared_lib} SHARED IMPORTED) + else() + set(lib_path "${CLANG_PREFIX}/lib/lib${shared_lib}${CMAKE_STATIC_LIBRARY_SUFFIX}") + string(REPLACE liblib lib lib_path ${lib_path}) + if(EXISTS "${lib_path}") + add_library(${shared_lib} STATIC IMPORTED) + else() + message(FATAL_ERROR "${shared_lib} library was not found in ${CLANG_PREFIX}/lib") + endif() + endif() + set_property(TARGET ${shared_lib} PROPERTY + IMPORTED_LOCATION ${lib_path}) + endforeach() + + #To prevent 'undefined symbol: _ZN4llvm23EnableABIBreakingChecksE' error: + add_compile_definitions(LLVM_DISABLE_ABI_BREAKING_CHECKS_ENFORCING) + + if(NOT ($ENV{target} MATCHES "darwin")) + execute_process(COMMAND /bin/sh -c "nm -D -C ${CLANG_PREFIX}/lib/libclang.so | grep -q abi:cxx11" RESULT_VARIABLE rc) + if(NOT (rc EQUAL 0)) #libclang.so compiled with cxx03 ABI + add_compile_options(-D_GLIBCXX_USE_CXX11_ABI=0) + endif() + endif() endif() - add_custom_target(version - ${CMAKE_COMMAND} - -D SRC=${CMAKE_SOURCE_DIR}/src/version.cpp.in - -D DST=${CMAKE_BINARY_DIR}/version.cpp - -D GIT_EXECUTABLE=${GIT_EXECUTABLE} - -P ${CMAKE_SOURCE_DIR}/version.cmake - DEPENDS src/version.cpp.in - ) + ${CMAKE_COMMAND} + -D SRC=${CMAKE_SOURCE_DIR}/src/version.cpp.in + -D DST=${CMAKE_BINARY_DIR}/version.cpp + -D GIT_EXECUTABLE=${GIT_EXECUTABLE} + -P ${CMAKE_SOURCE_DIR}/version.cmake + DEPENDS src/version.cpp.in + ) # The target 'versions' is used to produce version.cpp # This dummy custom command is defined to allow # inclusion of version.cpp dependency to the # wrapit executable. add_custom_command(OUTPUT version.cpp - COMMAND true - ) + COMMAND true + ) add_executable(wrapit - src/TypeRcd.cpp - src/TypeMapper.cpp - src/utils.cpp - src/cxxwrap_version.cpp - src/uuid_utils.cpp - src/libclang-ext.cpp - src/FunctionWrapper.cpp - src/CodeTree.cpp - src/main.cpp - src/toml.hpp - src/md5sum.cpp - src/FileTimeRestorer.cpp - src/Graph.cpp - version.cpp + src/TypeRcd.cpp + src/TypeMapper.cpp + src/utils.cpp + src/cxxwrap_version.cpp + src/uuid_utils.cpp + src/libclang-ext.cpp + src/FunctionWrapper.cpp + src/CodeTree.cpp + src/main.cpp + src/toml.hpp + src/md5sum.cpp + src/FileTimeRestorer.cpp + src/Graph.cpp + version.cpp ) add_dependencies(wrapit version) + +if(BUILD_LLVM) + if(APPLE) + set_target_properties(wrapit PROPERTIES INSTALL_RPATH @loader_path/../lib) + else() + set_target_properties(wrapit PROPERTIES INSTALL_RPATH $ORIGIN/../lib) + endif() + + target_include_directories(wrapit PRIVATE + ${llvm_SOURCE_DIR}/include + ${clang_SOURCE_DIR}/include + ${llvm_BINARY_DIR}/tools/clang/include + ${llvm_BINARY_DIR}/include) +endif() + target_link_libraries(wrapit PRIVATE libclang clang-cpp LLVM cxxopts dl - OpenSSL::Crypto) + OpenSSL::Crypto + #- gcc < 9.0 needs std++fs for the std::filesystem support + $<$,$,9.0>>:stdc++fs> +) set_target_properties(wrapit PROPERTIES - CXX_STANDARD 17 - OUTPUT_NAME wrapit - POSITION_INDEPENDENT_CODE ON #required for dladdrr on Linux (*) - ) + CXX_STANDARD 17 + OUTPUT_NAME wrapit + POSITION_INDEPENDENT_CODE ON #required for dladdrr on Linux (*) + ) configure_file(src/config.h.in config.h @ONLY) include_directories(${CMAKE_CURRENT_BINARY_DIR}) #contains the generated config.h header file diff --git a/test/runtests.jl b/test/runtests.jl index a8f2337..4b42401 100755 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -38,14 +38,15 @@ ENV["LOAD_PATH"] = "@:@stdlib" println("Try to run cmake...") #cmake based build # Configure and build with CMake - run(`cmake --fresh -S $source_dir -B $build_dir`) - run(`cmake --build $build_dir -t clean`) - run(`cmake --build $build_dir -j $ncores`) + rm(`rm -rf "$build_dir"`) + run(`cmake S "$source_dir" -B "$build_dir"`) + run(`cmake --build "$build_dir" -t clean`) + run(`cmake --build "$build_dir" -j $ncores`) else println("source_dir:", source_dir) #assumes plain make build - run(`make -C $source_dir clean`) - run(`make -C $source_dir -j $ncores`) + run(`make -C "$source_dir" clean`) + run(`make -C "$source_dir" -j $ncores`) end true catch