diff --git a/dependencies/.dockerignore b/dependencies/.dockerignore new file mode 100644 index 00000000..e52cffe2 --- /dev/null +++ b/dependencies/.dockerignore @@ -0,0 +1,2 @@ +build*/ +install*/ \ No newline at end of file diff --git a/dependencies/.gitignore b/dependencies/.gitignore new file mode 100644 index 00000000..e52cffe2 --- /dev/null +++ b/dependencies/.gitignore @@ -0,0 +1,2 @@ +build*/ +install*/ \ No newline at end of file diff --git a/dependencies/CMakeLists.txt b/dependencies/CMakeLists.txt new file mode 100644 index 00000000..4feda353 --- /dev/null +++ b/dependencies/CMakeLists.txt @@ -0,0 +1,50 @@ +# https://alexreinking.com/blog/how-to-use-cmake-without-the-agonizing-pain-part-1.html +cmake_minimum_required(VERSION 3.21) + +project(cxx-common) + +option(USE_EXTERNAL_LLVM "Do not compile LLVM as part of the superbuild, use an external one instead" OFF) +option(USE_SANITIZERS "Use ASan and UBSan" OFF) + +if(USE_EXTERNAL_LLVM) + if(CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin" AND NOT CMAKE_PREFIX_PATH) + execute_process( + COMMAND brew --prefix llvm + RESULT_VARIABLE BREW_LLVM + OUTPUT_VARIABLE BREW_LLVM_PREFIX + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(BREW_LLVM EQUAL 0 AND EXISTS "${BREW_LLVM_PREFIX}") + set(CMAKE_PREFIX_PATH "${BREW_LLVM_PREFIX}") + message(STATUS "Found LLVM keg installed by Homebrew at ${BREW_LLVM_PREFIX}") + else() + message(FATAL_ERROR "LLVM not found, to install: brew install llvm") + endif() + endif() + find_package(LLVM CONFIG REQUIRED) + message(STATUS "LLVM ${LLVM_PACKAGE_VERSION}: ${LLVM_DIR}") +endif() + +if(USE_SANITIZERS) + list(APPEND CMAKE_C_FLAGS "-fsanitize=address,undefined") + list(APPEND CMAKE_CXX_FLAGS "-fsanitize=address,undefined") +endif() + +include(superbuild.cmake) + +simple_git(https://github.com/gflags/gflags 52e94563eba1968783864942fedf6e87e3c611f4 +) +simple_git(https://github.com/google/glog v0.7.1 + "-DGFLAGS_USE_TARGET_NAMESPACE:STRING=ON" + "-DBUILD_TESTING:STRING=OFF" +) +simple_git(https://github.com/google/googletest v1.17.0 + "-Dgtest_force_shared_crt:STRING=ON" + "-DGFLAGS_USE_TARGET_NAMESPACE:STRING=ON" +) + +include(xed.cmake) + +if(NOT USE_EXTERNAL_LLVM) + include(llvm.cmake) +endif() diff --git a/dependencies/README.md b/dependencies/README.md new file mode 100644 index 00000000..fc97e4b5 --- /dev/null +++ b/dependencies/README.md @@ -0,0 +1,12 @@ +# dependencies + +Alternative to `cxx-common` based on [LLVMParty/packages](https://github.com/LLVMParty/packages) (superbuild pattern). + +## Building + +```sh +cmake -B build -DCMAKE_BUILD_TYPE=Release +cmake --build build +``` + +This will create a [CMake prefix](https://cmake.org/cmake/help/latest/command/find_package.html#search-procedure), which you pass to your project with `-DCMAKE_PREFIX_PATH=/path/to/dependencies/install`. See [presentation.md](https://github.com/LLVMParty/packages/blob/main/presentation.md) and [dependencies.md](https://github.com/LLVMParty/packages/blob/main/dependencies.md) for more information. diff --git a/dependencies/XEDConfig.cmake.in b/dependencies/XEDConfig.cmake.in new file mode 100644 index 00000000..c720e83c --- /dev/null +++ b/dependencies/XEDConfig.cmake.in @@ -0,0 +1,25 @@ +# /Users/admin/Projects/cxx-common/ports/xed/XEDConfig.cmake + +if(XED_FOUND) + return() +endif() + +get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE) + +find_library(XED_LIBRARY xed PATHS "${PACKAGE_PREFIX_DIR}/lib" NO_CACHE REQUIRED NO_DEFAULT_PATH) +add_library(XED::XED STATIC IMPORTED) +set_target_properties(XED::XED PROPERTIES + IMPORTED_CONFIGURATIONS "NOCONFIG" + IMPORTED_LOCATION_NOCONFIG "${XED_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${PACKAGE_PREFIX_DIR}/include" +) + +find_library(ILD_LIBRARY xed-ild PATHS "${PACKAGE_PREFIX_DIR}/lib" NO_CACHE REQUIRED NO_DEFAULT_PATH) +add_library(XED::ILD STATIC IMPORTED) +set_target_properties(XED::ILD PROPERTIES + IMPORTED_CONFIGURATIONS "NOCONFIG" + IMPORTED_LOCATION_NOCONFIG "${XED_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${PACKAGE_PREFIX_DIR}/include" +) + +set(XED_FOUND ON) diff --git a/dependencies/llvm.cmake b/dependencies/llvm.cmake new file mode 100644 index 00000000..c61f1157 --- /dev/null +++ b/dependencies/llvm.cmake @@ -0,0 +1,40 @@ +option(LLVM_ENABLE_ASSERTIONS "Enable assertions in LLVM" ON) + +# Default values for LLVM_URL and LLVM_SHA256. This is required because "-DLLVM_URL=" would be an empty URL +if("${LLVM_URL}" STREQUAL "") + set(LLVM_URL "https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/llvm-project-17.0.6.src.tar.xz") +endif() +if("${LLVM_SHA256}" STREQUAL "") + set(LLVM_SHA256 "58a8818c60e6627064f312dbf46c02d9949956558340938b71cf731ad8bc0813") +endif() + +set(LLVM_ARGS + "-DLLVM_ENABLE_PROJECTS:STRING=lld;clang;clang-tools-extra" + "-DLLVM_ENABLE_ASSERTIONS:STRING=${LLVM_ENABLE_ASSERTIONS}" + "-DLLVM_ENABLE_DUMP:STRING=${LLVM_ENABLE_ASSERTIONS}" + "-DLLVM_ENABLE_RTTI:STRING=ON" + "-DLLVM_ENABLE_LIBEDIT:STRING=OFF" + "-DLLVM_PARALLEL_LINK_JOBS:STRING=1" + "-DLLVM_ENABLE_DIA_SDK:STRING=OFF" + # This is meant for LLVM development, we use the DYLIB option instead + "-DBUILD_SHARED_LIBS:STRING=OFF" + "-DLLVM_LINK_LLVM_DYLIB:STRING=${BUILD_SHARED_LIBS}" +) + +if(USE_SANITIZERS) + list(APPEND LLVM_ARGS "-DLLVM_USE_SANITIZER:STRING=Address;Undefined") +endif() + +ExternalProject_Add(llvm + URL + ${LLVM_URL} + URL_HASH + "SHA256=${LLVM_SHA256}" + CMAKE_CACHE_ARGS + ${CMAKE_ARGS} + ${LLVM_ARGS} + CMAKE_GENERATOR + "Ninja" + SOURCE_SUBDIR + "llvm" +) diff --git a/dependencies/superbuild.cmake b/dependencies/superbuild.cmake new file mode 100644 index 00000000..e45d5033 --- /dev/null +++ b/dependencies/superbuild.cmake @@ -0,0 +1,161 @@ +include_guard() + +option(BUILD_SHARED_LIBS "Build using shared libraries" OFF) + +# Bail out early for multi-config generators +if(CMAKE_CONFIGURATION_TYPES) + message(FATAL_ERROR "Multi-config generators are not supported. Use Make/NMake/Ninja instead") +endif() + +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) + message(FATAL_ERROR "In-tree builds are not supported. Run CMake from a separate directory: cmake -B build") +endif() + +# Default to a Release config +set(CMAKE_BUILD_TYPE "Release" CACHE STRING "") +if(CMAKE_BUILD_TYPE STREQUAL "") + set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE) +endif() + +message(STATUS "Configuration: ${CMAKE_BUILD_TYPE}") + +# Default to build/install (setting this variable is not recommended and might cause conflicts) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/../install" CACHE PATH "Install prefix" FORCE) +endif() +message(STATUS "Install prefix: ${CMAKE_INSTALL_PREFIX}") + +# Save the host platform in the install prefix +make_directory(${CMAKE_INSTALL_PREFIX}) +file(TOUCH ${CMAKE_INSTALL_PREFIX}/${CMAKE_SYSTEM}.build) + +# Git is necessary for submodules +find_package(Git REQUIRED) +message(STATUS "Git: ${GIT_EXECUTABLE}") + +# Ninja is necessary for building the dependencies +find_program(ninja_EXECUTABLE ninja NO_CACHE NO_PACKAGE_ROOT_PATH NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH NO_CMAKE_INSTALL_PREFIX NO_CMAKE_FIND_ROOT_PATH) +if(ninja_EXECUTABLE STREQUAL "ninja_EXECUTABLE-NOTFOUND") + message(FATAL_ERROR "Could not find 'ninja' in the PATH") +endif() +message(STATUS "Ninja: ${ninja_EXECUTABLE}") + +# Documentation: https://cmake.org/cmake/help/latest/module/ExternalProject.html +include(ExternalProject) + +# Hook for ExternalProject_Add to make sure projects build in order +function(ExternalProject_Add name) + # The DEPENDS argument is fully implicit + cmake_parse_arguments(HOOK "" "" DEPENDS ${ARGN}) + if(HOOK_DEPENDS) + message(FATAL_ERROR "Explicit DEPENDS (${HOOK_DEPENDS}) not supported") + endif() + + # Update the LAST_EXTERNAL_PROJECT property + get_property(LAST_EXTERNAL_PROJECT GLOBAL PROPERTY LAST_EXTERNAL_PROJECT) + set_property(GLOBAL PROPERTY LAST_EXTERNAL_PROJECT ${name}) + + # Pass the previous project as a dependency to this call + if(LAST_EXTERNAL_PROJECT) + set(HOOK_ARGS DEPENDS "${LAST_EXTERNAL_PROJECT}") + message(STATUS "ExternalProject: ${name} depends on ${LAST_EXTERNAL_PROJECT}") + else() + message(STATUS "ExternalProject: ${name}") + endif() + _ExternalProject_Add(${name} ${ARGN} ${HOOK_ARGS} + # Reference: https://www.scivision.dev/cmake-external-project-ninja-verbose/ + USES_TERMINAL_DOWNLOAD ON + USES_TERMINAL_UPDATE ON + USES_TERMINAL_PATCH ON + USES_TERMINAL_CONFIGURE ON + USES_TERMINAL_BUILD ON + USES_TERMINAL_INSTALL ON + USES_TERMINAL_TEST ON + DOWNLOAD_EXTRACT_TIMESTAMP ON + ) +endfunction() + +if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + if(CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC") + # Suppress warnings for clang-cl builds, some of these cause compilation errors. + list(APPEND ADDITIONAL_FLAGS "-w") + elseif(UNIX AND NOT APPLE) + # To compile shared libraries, everything needs to be compiled as position independent code when using clang on linux + list(APPEND ADDITIONAL_FLAGS "-fPIC") + endif() +endif() + +# Convert a CMake list to a space-separated list +list(JOIN ADDITIONAL_FLAGS " " ADDITIONAL_FLAGS) + +# Default cache variables for all projects +list(APPEND CMAKE_ARGS + "-DCMAKE_PREFIX_PATH:FILEPATH=${CMAKE_INSTALL_PREFIX};${CMAKE_PREFIX_PATH}" + "-DCMAKE_INSTALL_PREFIX:FILEPATH=${CMAKE_INSTALL_PREFIX}" + "-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}" + "-DBUILD_SHARED_LIBS:STRING=${BUILD_SHARED_LIBS}" + "-DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER}" + "-DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER}" + "-DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS} ${ADDITIONAL_FLAGS}" + "-DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} ${ADDITIONAL_FLAGS}" +) + +if(CMAKE_C_COMPILER_LAUNCHER) + list(APPEND CMAKE_ARGS "-DCMAKE_C_COMPILER_LAUNCHER:STRING=${CMAKE_C_COMPILER_LAUNCHER}") +endif() +if(CMAKE_CXX_COMPILER_LAUNCHER) + list(APPEND CMAKE_ARGS "-DCMAKE_CXX_COMPILER_LAUNCHER:STRING=${CMAKE_CXX_COMPILER_LAUNCHER}") +endif() + +message(STATUS "Compiling all dependencies with the following CMake arguments:") +foreach(CMAKE_ARG ${CMAKE_ARGS}) + message("\t${CMAKE_ARG}") +endforeach() + +function(simple_git repo tag) + get_filename_component(name "${repo}" NAME_WE) + ExternalProject_Add(${name} + GIT_REPOSITORY + "${repo}" + GIT_TAG + "${tag}" + GIT_PROGRESS + ON + CMAKE_CACHE_ARGS + ${CMAKE_ARGS} + ${ARGN} + CMAKE_GENERATOR + "Ninja" + ) +endfunction() + +function(simple_submodule folder) + set(folder_path "${CMAKE_CURRENT_SOURCE_DIR}/${folder}") + if(NOT EXISTS "${folder_path}" OR NOT EXISTS "${folder_path}/CMakeLists.txt") + message(STATUS "Submodule '${folder}' not initialized, running git...") + execute_process( + COMMAND "${GIT_EXECUTABLE}" rev-parse --show-toplevel + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + OUTPUT_VARIABLE git_root + OUTPUT_STRIP_TRAILING_WHITESPACE + COMMAND_ERROR_IS_FATAL ANY + ) + execute_process( + COMMAND "${GIT_EXECUTABLE}" submodule update --init + WORKING_DIRECTORY "${git_root}" + COMMAND_ERROR_IS_FATAL ANY + ) + endif() + ExternalProject_Add(${folder} + SOURCE_DIR + "${folder_path}" + CMAKE_CACHE_ARGS + ${CMAKE_ARGS} + ${ARGN} + CMAKE_GENERATOR + "Ninja" + # Always trigger the build step (necessary because there is no download step) + BUILD_ALWAYS + ON + ) +endfunction() diff --git a/dependencies/xed.cmake b/dependencies/xed.cmake new file mode 100644 index 00000000..cbc1582f --- /dev/null +++ b/dependencies/xed.cmake @@ -0,0 +1,88 @@ +find_package(Python3 COMPONENTS Interpreter REQUIRED) +message(STATUS "Python3: ${Python3_EXECUTABLE}") + +# Reference: https://github.com/lifting-bits/cxx-common/blob/e0063b2f5986582ed8dcab0c2863abf0893b3082/ports/xed/portfile.cmake + +# TODO: pass compiler flags + +if(CMAKE_SYSTEM_NAME STREQUAL "Windows" AND MSVC) + set(compiler ms) #msvc or clang-cl +elseif(CMAKE_CXX_COMPILER_ID MATCHES "^(Apple)?Clang$") + set(compiler clang) +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(compiler gnu) +else() + message(FATAL_ERROR "Unknown compiler: ${CMAKE_CXX_COMPILER_ID}") +endif() + +set(MFILE_ARGS + "install" + "--install-dir=install" + "--cc=${CMAKE_C_COMPILER}" + "--cxx=${CMAKE_CXX_COMPILER}" + "--compiler=${compiler}" +) + +if(CMAKE_OSX_SYSROOT) + list(APPEND MFILE_ARGS "--extra-ccflags=-isysroot ${CMAKE_OSX_SYSROOT}") + list(APPEND MFILE_ARGS "--extra-cxxflags=-isysroot ${CMAKE_OSX_SYSROOT}") +endif() + +if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + list(APPEND MFILE_ARGS "--extra-ccflags=${ADDITIONAL_FLAGS}") + list(APPEND MFILE_ARGS "--extra-cxxflags=${ADDITIONAL_FLAGS}") +endif() + +if(USE_SANITIZERS) + list(APPEND MFILE_ARGS "--extra-ccflags=-fsanitize=address,undefined") + list(APPEND MFILE_ARGS "--extra-cxxflags=-fsanitize=address,undefined") +endif() + +if(BUILD_SHARED_LIBS) + list(APPEND MFILE_ARGS "--shared") +else() + list(APPEND MFILE_ARGS "--static") +endif() + +if(CMAKE_AR) + list(APPEND MFILE_ARGS "--ar=${CMAKE_AR}") +endif() + +ExternalProject_Add(mbuild + GIT_REPOSITORY + "https://github.com/intelxed/mbuild" + GIT_TAG + "v2022.04.17" + GIT_PROGRESS + ON + CONFIGURE_COMMAND + "${CMAKE_COMMAND}" -E true + BUILD_COMMAND + "${CMAKE_COMMAND}" -E true + INSTALL_COMMAND + "${CMAKE_COMMAND}" -E true + PREFIX + xed-prefix +) + +ExternalProject_Add(xed + GIT_REPOSITORY + "https://github.com/intelxed/xed" + GIT_TAG + "v2022.04.17" + GIT_PROGRESS + ON + CMAKE_CACHE_ARGS + ${CMAKE_ARGS} + CONFIGURE_COMMAND + "${CMAKE_COMMAND}" -E true + BUILD_COMMAND + "${Python3_EXECUTABLE}" "/mfile.py" ${MFILE_ARGS} + INSTALL_COMMAND + "${CMAKE_COMMAND}" -E copy_directory /install "${CMAKE_INSTALL_PREFIX}" + PREFIX + xed-prefix +) + +# TODO: generate XEDVersion.cmake as well file +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/XEDConfig.cmake.in" "${CMAKE_INSTALL_PREFIX}/lib/cmake/XED/XEDConfig.cmake" @ONLY)