diff options
Diffstat (limited to 'rcc/cmake/modules')
| -rw-r--r-- | rcc/cmake/modules/AddOCaml.cmake | 239 | ||||
| -rw-r--r-- | rcc/cmake/modules/AddRCC.cmake | 184 | ||||
| -rw-r--r-- | rcc/cmake/modules/CMakeLists.txt | 47 | ||||
| -rw-r--r-- | rcc/cmake/modules/CheckAtomic.cmake | 125 | ||||
| -rw-r--r-- | rcc/cmake/modules/CheckCompilerVersion.cmake | 110 | ||||
| -rw-r--r-- | rcc/cmake/modules/CheckProblematicConfigurations.cmake | 19 | ||||
| -rw-r--r-- | rcc/cmake/modules/DetermineGCCCompatible.cmake | 13 | ||||
| -rw-r--r-- | rcc/cmake/modules/FindFFI.cmake | 106 | ||||
| -rw-r--r-- | rcc/cmake/modules/FindLibEdit.cmake | 65 | ||||
| -rw-r--r-- | rcc/cmake/modules/FindLibpfm.cmake | 37 | ||||
| -rw-r--r-- | rcc/cmake/modules/FindOCaml.cmake | 103 | ||||
| -rw-r--r-- | rcc/cmake/modules/GetErrcMessages.cmake | 45 | ||||
| -rw-r--r-- | rcc/cmake/modules/GetHostTriple.cmake | 98 | ||||
| -rw-r--r-- | rcc/cmake/modules/HandleRCCOptions.cmake | 1182 | ||||
| -rw-r--r-- | rcc/cmake/modules/HandleRCCStdlib.cmake | 54 | ||||
| -rw-r--r-- | rcc/cmake/modules/RCCConfig.cmake.in | 27 | ||||
| -rw-r--r-- | rcc/cmake/modules/RCCConfigVersion.cmake.in | 13 |
17 files changed, 2467 insertions, 0 deletions
diff --git a/rcc/cmake/modules/AddOCaml.cmake b/rcc/cmake/modules/AddOCaml.cmake new file mode 100644 index 0000000..01fb5a1 --- /dev/null +++ b/rcc/cmake/modules/AddOCaml.cmake @@ -0,0 +1,239 @@ +# CMake build rules for the OCaml language. +# Assumes FindOCaml is used. +# http://ocaml.org/ +# +# Example usage: +# +# add_ocaml_library(pkg_a OCAML mod_a OCAMLDEP pkg_b C mod_a_stubs PKG ctypes RCC core) +# +# Unnamed parameters: +# +# * Library name. +# +# Named parameters: +# +# OCAML OCaml module names. Imply presence of a corresponding .ml and .mli files. +# OCAMLDEP Names of libraries this library depends on. +# C C stub sources. Imply presence of a corresponding .c file. +# CFLAGS Additional arguments passed when compiling C stubs. +# PKG Names of ocamlfind packages this library depends on. +# RCC Names of RCC libraries this library depends on. +# NOCOPY Do not automatically copy sources (.c, .ml, .mli) from the source directory, +# e.g. if they are generated. +# + +function(add_ocaml_library name) + CMAKE_PARSE_ARGUMENTS(ARG "NOCOPY" "" "OCAML;OCAMLDEP;C;CFLAGS;PKG;RCC" ${ARGN}) + + set(src ${CMAKE_CURRENT_SOURCE_DIR}) + set(bin ${CMAKE_CURRENT_BINARY_DIR}) + + set(ocaml_pkgs) + foreach( ocaml_pkg ${ARG_PKG} ) + list(APPEND ocaml_pkgs "-package" "${ocaml_pkg}") + endforeach() + + set(sources) + + set(ocaml_inputs) + + set(ocaml_outputs "${bin}/${name}.cma") + if( ARG_C ) + list(APPEND ocaml_outputs + "${bin}/lib${name}${CMAKE_STATIC_LIBRARY_SUFFIX}") + if ( BUILD_SHARED_LIBS ) + list(APPEND ocaml_outputs + "${bin}/dll${name}${CMAKE_SHARED_LIBRARY_SUFFIX}") + endif() + endif() + if( HAVE_OCAMLOPT ) + list(APPEND ocaml_outputs + "${bin}/${name}.cmxa" + "${bin}/${name}${CMAKE_STATIC_LIBRARY_SUFFIX}") + endif() + + set(ocaml_flags "-lstdc++" "-ldopt" "-L${RCC_LIBRARY_DIR}" + "-ccopt" "-L\\$CAMLORIGIN/../.." + "-ccopt" "-Wl,-rpath,\\$CAMLORIGIN/../.." + ${ocaml_pkgs}) + + set(ocaml_dep_inputs) + foreach( ocaml_dep ${ARG_OCAMLDEP} ) + get_target_property(dep_ocaml_flags "ocaml_${ocaml_dep}" OCAML_FLAGS) + list(APPEND ocaml_flags ${dep_ocaml_flags}) + get_target_property(dep_ocaml_outputs "ocaml_${ocaml_dep}" OCAML_OUTPUTS) + list(APPEND ocaml_dep_inputs ${dep_ocaml_outputs}) + endforeach() + + if( NOT BUILD_SHARED_LIBS ) + list(APPEND ocaml_flags "-custom") + endif() + + if(RCC_LINK_RCC_DYLIB) + list(APPEND ocaml_flags "-lRCC") + else() + explicit_map_components_to_libraries(rcc_libs ${ARG_RCC}) + foreach( rcc_lib ${rcc_libs} ) + list(APPEND ocaml_flags "-l${rcc_lib}" ) + endforeach() + + get_property(system_libs TARGET RCCSupport PROPERTY RCC_SYSTEM_LIBS) + foreach(system_lib ${system_libs}) + if (system_lib MATCHES "^-") + # If it's an option, pass it without changes. + list(APPEND ocaml_flags "${system_lib}" ) + else() + # Otherwise assume it's a library name we need to link with. + list(APPEND ocaml_flags "-l${system_lib}" ) + endif() + endforeach() + endif() + + string(REPLACE ";" " " ARG_CFLAGS "${ARG_CFLAGS}") + set(c_flags "${ARG_CFLAGS} ${RCC_DEFINITIONS}") + foreach( include_dir ${RCC_INCLUDE_DIR} ${RCC_MAIN_INCLUDE_DIR} ) + set(c_flags "${c_flags} -I${include_dir}") + endforeach() + # include -D/-UNDEBUG to match dump function visibility + # regex from HandleRCCOptions.cmake + string(REGEX MATCH "(^| )[/-][UD] *NDEBUG($| )" flag_matches + "${CMAKE_C_FLAGS_${uppercase_CMAKE_BUILD_TYPE}} ${CMAKE_C_FLAGS}") + set(c_flags "${c_flags} ${flag_matches}") + + foreach( ocaml_file ${ARG_OCAML} ) + list(APPEND sources "${ocaml_file}.mli" "${ocaml_file}.ml") + + list(APPEND ocaml_inputs "${bin}/${ocaml_file}.mli" "${bin}/${ocaml_file}.ml") + + list(APPEND ocaml_outputs "${bin}/${ocaml_file}.cmi" "${bin}/${ocaml_file}.cmo") + + list(APPEND ocaml_outputs "${bin}/${ocaml_file}.cmti" "${bin}/${ocaml_file}.cmt") + + if( HAVE_OCAMLOPT ) + list(APPEND ocaml_outputs + "${bin}/${ocaml_file}.cmx" + "${bin}/${ocaml_file}${CMAKE_C_OUTPUT_EXTENSION}") + endif() + endforeach() + + foreach( c_file ${ARG_C} ) + list(APPEND sources "${c_file}.c") + + list(APPEND c_inputs "${bin}/${c_file}.c") + list(APPEND c_outputs "${bin}/${c_file}${CMAKE_C_OUTPUT_EXTENSION}") + endforeach() + + if( NOT ARG_NOCOPY ) + foreach( source ${sources} ) + add_custom_command( + OUTPUT "${bin}/${source}" + COMMAND "${CMAKE_COMMAND}" "-E" "copy" "${src}/${source}" "${bin}" + DEPENDS "${src}/${source}" + COMMENT "Copying ${source} to build area") + endforeach() + endif() + + foreach( c_input ${c_inputs} ) + get_filename_component(basename "${c_input}" NAME_WE) + add_custom_command( + OUTPUT "${basename}${CMAKE_C_OUTPUT_EXTENSION}" + COMMAND "${OCAMLFIND}" "ocamlc" "-c" "${c_input}" -ccopt ${c_flags} + DEPENDS "${c_input}" + COMMENT "Building OCaml stub object file ${basename}${CMAKE_C_OUTPUT_EXTENSION}" + VERBATIM) + endforeach() + + set(ocaml_params) + foreach( ocaml_input ${ocaml_inputs} ${c_outputs}) + get_filename_component(filename "${ocaml_input}" NAME) + list(APPEND ocaml_params "${filename}") + endforeach() + + if( APPLE ) + set(ocaml_rpath "@executable_path/../../../lib${RCC_LIBDIR_SUFFIX}") + elseif( UNIX ) + set(ocaml_rpath "\\$ORIGIN/../../../lib${RCC_LIBDIR_SUFFIX}") + endif() + list(APPEND ocaml_flags "-ldopt" "-Wl,-rpath,${ocaml_rpath}") + + add_custom_command( + OUTPUT ${ocaml_outputs} + COMMAND "${OCAMLFIND}" "ocamlmklib" "-ocamlcflags" "-bin-annot" + "-o" "${name}" ${ocaml_flags} ${ocaml_params} + DEPENDS ${ocaml_inputs} ${ocaml_dep_inputs} ${c_outputs} + COMMENT "Building OCaml library ${name}" + VERBATIM) + + add_custom_command( + OUTPUT "${bin}/${name}.odoc" + COMMAND "${OCAMLFIND}" "ocamldoc" + "-I" "${bin}" + "-I" "${RCC_LIBRARY_DIR}/ocaml/rcc/" + "-dump" "${bin}/${name}.odoc" + ${ocaml_pkgs} ${ocaml_inputs} + DEPENDS ${ocaml_inputs} ${ocaml_dep_inputs} ${ocaml_outputs} + COMMENT "Building OCaml documentation for ${name}" + VERBATIM) + + add_custom_target("ocaml_${name}" ALL DEPENDS ${ocaml_outputs} "${bin}/${name}.odoc") + get_subproject_title(subproject_title) + set_target_properties("ocaml_${name}" PROPERTIES FOLDER "${subproject_title}/Bindings/OCaml") + + set_target_properties("ocaml_${name}" PROPERTIES + OCAML_FLAGS "-I;${bin}") + set_target_properties("ocaml_${name}" PROPERTIES + OCAML_ODOC "${bin}/${name}.odoc") + set_target_properties("ocaml_${name}" PROPERTIES + OCAML_OUTPUTS "${ocaml_outputs}") + + foreach( ocaml_dep ${ARG_OCAMLDEP} ) + add_dependencies("ocaml_${name}" "ocaml_${ocaml_dep}") + endforeach() + + if( NOT RCC_OCAML_OUT_OF_TREE ) + foreach( rcc_lib ${rcc_libs} ) + add_dependencies("ocaml_${name}" "${rcc_lib}") + endforeach() + endif() + + add_dependencies("ocaml_all" "ocaml_${name}") + + set(install_files) + set(install_shlibs) + foreach( ocaml_output ${ocaml_inputs} ${ocaml_outputs} ) + get_filename_component(ext "${ocaml_output}" EXT) + + if( NOT (ext STREQUAL ".cmo" OR + ext STREQUAL ".ml" OR + ext STREQUAL CMAKE_C_OUTPUT_EXTENSION OR + ext STREQUAL CMAKE_SHARED_LIBRARY_SUFFIX) ) + list(APPEND install_files "${ocaml_output}") + elseif( ext STREQUAL CMAKE_SHARED_LIBRARY_SUFFIX) + list(APPEND install_shlibs "${ocaml_output}") + endif() + endforeach() + + install(FILES ${install_files} + DESTINATION "${RCC_OCAML_INSTALL_PATH}/rcc") + install(FILES ${install_shlibs} + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE + DESTINATION "${RCC_OCAML_INSTALL_PATH}/stublibs") + + foreach( install_file ${install_files} ${install_shlibs} ) + get_filename_component(filename "${install_file}" NAME) + add_custom_command(TARGET "ocaml_${name}" POST_BUILD + COMMAND "${CMAKE_COMMAND}" "-E" "copy" "${install_file}" + "${RCC_LIBRARY_DIR}/ocaml/rcc/" + COMMENT "Copying OCaml library component ${filename} to intermediate area" + VERBATIM) + add_dependencies("ocaml_${name}" ocaml_make_directory) + endforeach() +endfunction() + +add_custom_target(ocaml_make_directory + COMMAND "${CMAKE_COMMAND}" "-E" "make_directory" "${RCC_LIBRARY_DIR}/ocaml/rcc") +add_custom_target("ocaml_all") +set_target_properties(ocaml_all PROPERTIES FOLDER "RCC/Bindings/OCaml") +set_target_properties(ocaml_make_directory PROPERTIES FOLDER "RCC/Bindings/OCaml") diff --git a/rcc/cmake/modules/AddRCC.cmake b/rcc/cmake/modules/AddRCC.cmake new file mode 100644 index 0000000..11bd92e --- /dev/null +++ b/rcc/cmake/modules/AddRCC.cmake @@ -0,0 +1,184 @@ +# SPDX-License-Identifier: GPL-3.0-or-later + +include_guard(GLOBAL) +include(GNUInstallDirs) +include(HandleRCCOptions) + +macro(rcc_configure_output_directories) + set(RCC_RUNTIME_OUTPUT_INTDIR "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin") + set(RCC_LIBRARY_OUTPUT_INTDIR "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib") + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${RCC_RUNTIME_OUTPUT_INTDIR}") + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${RCC_LIBRARY_OUTPUT_INTDIR}") + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${RCC_LIBRARY_OUTPUT_INTDIR}") +endmacro() + +function(rcc_set_output_directory target) + if(WIN32 OR CYGWIN) + set(moduleDir "${RCC_RUNTIME_OUTPUT_INTDIR}") + else() + set(moduleDir "${RCC_LIBRARY_OUTPUT_INTDIR}") + endif() + if(NOT CMAKE_CFG_INTDIR STREQUAL ".") + foreach(buildMode IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER "${buildMode}" configSuffix) + if(RCC_RUNTIME_OUTPUT_INTDIR) + string(REPLACE "${CMAKE_CFG_INTDIR}" "${buildMode}" binaryDir "${RCC_RUNTIME_OUTPUT_INTDIR}") + set_target_properties(${target} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_${configSuffix} "${binaryDir}") + endif() + if(RCC_LIBRARY_OUTPUT_INTDIR) + string(REPLACE "${CMAKE_CFG_INTDIR}" "${buildMode}" libraryDir "${RCC_LIBRARY_OUTPUT_INTDIR}") + set_target_properties(${target} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY_${configSuffix} "${libraryDir}") + endif() + if(moduleDir) + string(REPLACE "${CMAKE_CFG_INTDIR}" "${buildMode}" configModuleDir "${moduleDir}") + set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${configSuffix} "${configModuleDir}") + endif() + endforeach() + else() + if(RCC_RUNTIME_OUTPUT_INTDIR) + set_target_properties(${target} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${RCC_RUNTIME_OUTPUT_INTDIR}") + endif() + if(RCC_LIBRARY_OUTPUT_INTDIR) + set_target_properties(${target} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${RCC_LIBRARY_OUTPUT_INTDIR}") + endif() + if(moduleDir) + set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${moduleDir}") + endif() + endif() +endfunction() + +function(rcc_update_pch target) + if(RCC_REQUIRES_RTTI OR RCC_REQUIRES_EH) + set(arg_DISABLE_PCH_REUSE ON) + endif() + get_target_property(sources ${target} SOURCES) + foreach(source IN LISTS sources) + get_filename_component(extension "${source}" EXT) + if(extension STREQUAL ".c" AND NOT arg_PRECOMPILE_HEADERS) + set(arg_DISABLE_PCH_REUSE ON) + elseif(extension STREQUAL ".mm") + set(arg_DISABLE_PCH_REUSE ON) + endif() + endforeach() + get_target_property(targetType ${target} TYPE) + if(targetType STREQUAL "EXECUTABLE") + get_target_property(positionIndependent ${target} POSITION_INDEPENDENT_CODE) + if(positionIndependent) + set(arg_DISABLE_PCH_REUSE ON) + endif() + endif() + + set(pchPriority 0) + foreach(library IN LISTS arg_LINK_LIBS) + if(TARGET ${library}) + get_target_property(libraryPriority ${library} RCC_PCH_PRIORITY) + get_target_property(libraryPCHDisabled ${library} DISABLE_PRECOMPILE_HEADERS) + if(libraryPriority GREATER pchPriority AND NOT libraryPCHDisabled) + set(pchPriority "${libraryPriority}") + set(pchReuse "${library}") + endif() + endif() + endforeach() + if(arg_PRECOMPILE_HEADERS) + message(DEBUG "Adding PCH ${arg_PRECOMPILE_HEADERS} for ${target} (prio ${pchPriority})") + target_precompile_headers(${target} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:${arg_PRECOMPILE_HEADERS}>") + if(NOT arg_DISABLE_PCH_REUSE) + math(EXPR pchPriority "${pchPriority} + 1") + set_target_properties(${target} PROPERTIES RCC_PCH_PRIORITY "${pchPriority}") + endif() + elseif(pchReuse AND NOT arg_DISABLE_PCH_REUSE) + message(DEBUG "Using PCH ${pchReuse} for ${target} (prio ${pchPriority})") + target_precompile_headers(${target} REUSE_FROM ${pchReuse}) + else() + message(DEBUG "Using NO PCH for ${target}") + endif() +endfunction() + +function(rcc_setup_rpath target) + if(CMAKE_INSTALL_RPATH) + return() + endif() + set(extraLibraryDir "") + if(RCC_INSTALL_PREFIX AND NOT RCC_INSTALL_PREFIX STREQUAL CMAKE_INSTALL_PREFIX) + set(extraLibraryDir "${RCC_LIBRARY_DIR}") + elseif(RCC_BUILD_LIBRARY_DIR) + set(extraLibraryDir "${RCC_LIBRARY_DIR}") + endif() + get_target_property(targetType ${target} TYPE) + if(targetType STREQUAL "EXECUTABLE") + set(installDirectory "${CMAKE_INSTALL_FULL_BINDIR}") + else() + set(installDirectory "${CMAKE_INSTALL_FULL_LIBDIR}") + endif() + file(RELATIVE_PATH relativeLibraryDir "${installDirectory}" "${CMAKE_INSTALL_FULL_LIBDIR}") + + if(APPLE) + set(installName INSTALL_NAME_DIR "@rpath") + set(installRpath "@loader_path/${relativeLibraryDir}" ${extraLibraryDir}) + elseif(CMAKE_SYSTEM_NAME MATCHES "AIX" AND BUILD_SHARED_LIBS) + set(installRpath "${RCC_LIBRARY_OUTPUT_INTDIR}" "${CMAKE_INSTALL_FULL_LIBDIR}" ${extraLibraryDir}) + elseif(UNIX) + set(buildRpath "\$ORIGIN/../lib" ${extraLibraryDir}) + set(installRpath "\$ORIGIN/${relativeLibraryDir}") + if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD|DragonFly") + target_link_options(${target} PRIVATE "LINKER:-z,origin") + endif() + if(RCC_LINKER_IS_GNULD AND RCC_LIBRARY_OUTPUT_INTDIR) + target_link_options(${target} PRIVATE "LINKER:-rpath-link,${RCC_LIBRARY_OUTPUT_INTDIR}") + endif() + else() + return() + endif() + if("${CMAKE_BUILD_RPATH}" STREQUAL "") + if(CMAKE_SYSTEM_NAME MATCHES "Darwin|AIX") + set_target_properties(${target} PROPERTIES BUILD_WITH_INSTALL_RPATH ON) + else() + set_property(TARGET ${target} APPEND PROPERTY BUILD_RPATH "${buildRpath}") + endif() + endif() + set_target_properties(${target} PROPERTIES INSTALL_RPATH "${installRpath}" ${installName}) +endfunction() + +function(rcc_configure_target target) + rcc_apply_options(${target}) + rcc_set_output_directory(${target}) + rcc_update_pch(${target}) + get_target_property(targetType ${target} TYPE) + if(targetType MATCHES "^(EXECUTABLE|SHARED_LIBRARY|MODULE_LIBRARY)$" AND NOT arg_NO_INSTALL_RPATH) + rcc_setup_rpath(${target}) + endif() + if(targetType STREQUAL "SHARED_LIBRARY") + if(MSVC) + set_target_properties(${target} PROPERTIES PREFIX "") + endif() + if(UNIX) + set_target_properties(${target} PROPERTIES + VERSION "${RCC_VERSION_MAJOR}.${RCC_VERSION_MINOR}" + SOVERSION "${RCC_VERSION_MAJOR}.${RCC_VERSION_MINOR}") + endif() + endif() +endfunction() + +function(add_rcc_library name) + cmake_parse_arguments(PARSE_ARGV 1 arg "DISABLE_PCH_REUSE;NO_INSTALL_RPATH" "" "LINK_LIBS;PRECOMPILE_HEADERS") + add_library(${name} ${arg_UNPARSED_ARGUMENTS}) + target_link_libraries(${name} PUBLIC RCCHeaders ${arg_LINK_LIBS}) + rcc_configure_target(${name}) + install(TARGETS ${name} EXPORT RCCTargets + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") +endfunction() + +function(add_rcc_executable name) + cmake_parse_arguments(PARSE_ARGV 1 arg "DISABLE_PCH_REUSE;NO_INSTALL_RPATH" "" "LINK_LIBS;PRECOMPILE_HEADERS") + add_executable(${name} ${arg_UNPARSED_ARGUMENTS}) + target_link_libraries(${name} PRIVATE RCCHeaders ${arg_LINK_LIBS}) + rcc_configure_target(${name}) +endfunction() + +function(add_rcc_tool name) + add_rcc_executable(${name} ${ARGN}) + install(TARGETS ${name} EXPORT RCCTargets + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") +endfunction() diff --git a/rcc/cmake/modules/CMakeLists.txt b/rcc/cmake/modules/CMakeLists.txt new file mode 100644 index 0000000..39b6d97 --- /dev/null +++ b/rcc/cmake/modules/CMakeLists.txt @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: GPL-3.0-or-later + +include(CMakePackageConfigHelpers) + +get_directory_property(RCC_DEFINITIONS DIRECTORY "${RCC_SOURCE_DIR}" COMPILE_DEFINITIONS) +set(RCC_PACKAGE_MSVC_RUNTIME_LIBRARY "${CMAKE_MSVC_RUNTIME_LIBRARY}") +if(NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY) + set(RCC_PACKAGE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL") +endif() +set(rccPackageDir "${RCC_BINARY_DIR}/lib/cmake/RCC") +set(rccInstallPackageDir "${CMAKE_INSTALL_LIBDIR}/cmake/RCC") +set(RCC_PACKAGE_MODULE_DIR "${RCC_CMAKE_DIR}") +set(RCC_PACKAGE_INCLUDE_DIRS "${RCC_INCLUDE_DIRS}") +set(RCC_PACKAGE_LIBRARY_DIR "${RCC_LIBRARY_DIR}") +set(RCC_PACKAGE_BUILD_LIBRARY_DIR "${RCC_LIBRARY_DIR}") +set(RCC_PACKAGE_INSTALL_PREFIX "") +configure_package_config_file(RCCConfig.cmake.in "${rccPackageDir}/RCCConfig.cmake" + INSTALL_DESTINATION "${rccPackageDir}" + NO_SET_AND_CHECK_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO) +export(EXPORT RCCTargets FILE "${rccPackageDir}/RCCTargets.cmake") + +set(RCC_PACKAGE_MODULE_DIR "\${CMAKE_CURRENT_LIST_DIR}") +if(IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}") + set(RCC_PACKAGE_INCLUDE_DIRS "${CMAKE_INSTALL_INCLUDEDIR}") +else() + set(RCC_PACKAGE_INCLUDE_DIRS "\${PACKAGE_PREFIX_DIR}/${CMAKE_INSTALL_INCLUDEDIR}") +endif() +if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}") + set(RCC_PACKAGE_LIBRARY_DIR "${CMAKE_INSTALL_LIBDIR}") +else() + set(RCC_PACKAGE_LIBRARY_DIR "\${PACKAGE_PREFIX_DIR}/${CMAKE_INSTALL_LIBDIR}") +endif() +set(RCC_PACKAGE_BUILD_LIBRARY_DIR "") +set(RCC_PACKAGE_INSTALL_PREFIX "\${PACKAGE_PREFIX_DIR}") +configure_package_config_file(RCCConfig.cmake.in RCCConfig.install.cmake + INSTALL_DESTINATION "${rccInstallPackageDir}" + NO_SET_AND_CHECK_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO) +configure_file(RCCConfigVersion.cmake.in + "${rccPackageDir}/RCCConfigVersion.cmake" @ONLY) +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/RCCConfig.install.cmake" + DESTINATION "${rccInstallPackageDir}" RENAME RCCConfig.cmake) +install(FILES + "${rccPackageDir}/RCCConfigVersion.cmake" + AddRCC.cmake HandleRCCOptions.cmake + DESTINATION "${rccInstallPackageDir}") +install(EXPORT RCCTargets FILE RCCTargets.cmake + DESTINATION "${rccInstallPackageDir}") diff --git a/rcc/cmake/modules/CheckAtomic.cmake b/rcc/cmake/modules/CheckAtomic.cmake new file mode 100644 index 0000000..b9ec06e --- /dev/null +++ b/rcc/cmake/modules/CheckAtomic.cmake @@ -0,0 +1,125 @@ +# atomic builtins are required for threading support. + +INCLUDE(CheckCXXSourceCompiles) +INCLUDE(CheckLibraryExists) + +# Sometimes linking against libatomic is required for atomic ops, if +# the platform doesn't support lock-free atomics. + +function(check_working_cxx_atomics varname) + set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++11") + CHECK_CXX_SOURCE_COMPILES(" +#include <atomic> +std::atomic<int> x; +std::atomic<short> y; +std::atomic<char> z; +int main() { + ++z; + ++y; + return ++x; +} +" ${varname}) + set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS}) +endfunction(check_working_cxx_atomics) + +function(check_working_cxx_atomics64 varname) + set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) + set(CMAKE_REQUIRED_FLAGS "-std=c++11 ${CMAKE_REQUIRED_FLAGS}") + CHECK_CXX_SOURCE_COMPILES(" +#include <atomic> +#include <cstdint> +std::atomic<uint64_t> x (0); +int main() { + uint64_t i = x.load(std::memory_order_relaxed); + (void)i; + return 0; +} +" ${varname}) + set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS}) +endfunction(check_working_cxx_atomics64) + + +# Check for (non-64-bit) atomic operations. +if(MSVC) + set(HAVE_CXX_ATOMICS_WITHOUT_LIB True) +elseif(RCC_COMPILER_IS_GCC_COMPATIBLE OR CMAKE_CXX_COMPILER_ID MATCHES "XL") + # First check if atomics work without the library. + check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITHOUT_LIB) + # If not, check if the library exists, and atomics work with it. + if(NOT HAVE_CXX_ATOMICS_WITHOUT_LIB) + check_library_exists(atomic __atomic_fetch_add_4 "" HAVE_LIBATOMIC) + if(HAVE_LIBATOMIC) + list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic") + check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITH_LIB) + if (NOT HAVE_CXX_ATOMICS_WITH_LIB) + message(FATAL_ERROR "Host compiler must support std::atomic!") + endif() + else() + message(FATAL_ERROR "Host compiler appears to require libatomic, but cannot find it.") + endif() + endif() +endif() + +# Check for 64 bit atomic operations. +if(MSVC) + set(HAVE_CXX_ATOMICS64_WITHOUT_LIB True) +elseif(RCC_COMPILER_IS_GCC_COMPATIBLE OR CMAKE_CXX_COMPILER_ID MATCHES "XL") + # First check if atomics work without the library. + check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITHOUT_LIB) + # If not, check if the library exists, and atomics work with it. + if(NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB) + check_library_exists(atomic __atomic_load_8 "" HAVE_CXX_LIBATOMICS64) + if(HAVE_CXX_LIBATOMICS64) + list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic") + check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITH_LIB) + if (NOT HAVE_CXX_ATOMICS64_WITH_LIB) + message(FATAL_ERROR "Host compiler must support 64-bit std::atomic!") + endif() + else() + message(FATAL_ERROR "Host compiler appears to require libatomic for 64-bit operations, but cannot find it.") + endif() + endif() +endif() + +# Set variable RCC_ATOMIC_LIB specifying flags for linking against libatomic. +if(HAVE_CXX_ATOMICS_WITH_LIB OR HAVE_CXX_ATOMICS64_WITH_LIB) + # Use options --push-state, --as-needed and --pop-state if linker is known to support them. + # Use single option -Wl of compiler driver to avoid incorrect re-ordering of options by CMake. + if(RCC_LINKER_IS_GNULD OR RCC_LINKER_IS_GOLD OR RCC_LINKER_IS_LLD OR RCC_LINKER_IS_MOLD) + set(RCC_ATOMIC_LIB "-Wl,--push-state,--as-needed,-latomic,--pop-state") + else() + set(RCC_ATOMIC_LIB "-latomic") + endif() +else() + set(RCC_ATOMIC_LIB) +endif() + +## TODO: This define is only used for the legacy atomic operations in +## rcc's Atomic.h, which should be replaced. Other code simply +## assumes C++11 <atomic> works. +CHECK_CXX_SOURCE_COMPILES(" +#ifdef _MSC_VER +#include <windows.h> +#endif +int main() { +#ifdef _MSC_VER + volatile LONG val = 1; + MemoryBarrier(); + InterlockedCompareExchange(&val, 0, 1); + InterlockedIncrement(&val); + InterlockedDecrement(&val); +#else + volatile unsigned long val = 1; + __sync_synchronize(); + __sync_val_compare_and_swap(&val, 1, 0); + __sync_add_and_fetch(&val, 1); + __sync_sub_and_fetch(&val, 1); +#endif + return 0; + } +" RCC_HAS_ATOMICS) + +if( NOT RCC_HAS_ATOMICS ) + message(STATUS "Warning: RCC will be built thread-unsafe because atomic builtins are missing") +endif() diff --git a/rcc/cmake/modules/CheckCompilerVersion.cmake b/rcc/cmake/modules/CheckCompilerVersion.cmake new file mode 100644 index 0000000..7a9f964 --- /dev/null +++ b/rcc/cmake/modules/CheckCompilerVersion.cmake @@ -0,0 +1,110 @@ +# Check if the host compiler is new enough. +# These versions are updated based on the following policy: +# rcc.org/docs/DeveloperPolicy.html#toolchain + +include(CheckCXXSourceCompiles) + +set(GCC_MIN 7.4) +set(GCC_SOFT_ERROR 7.4) +set(CLANG_MIN 5.0) +set(CLANG_SOFT_ERROR 5.0) +set(APPLECLANG_MIN 10.0) +set(APPLECLANG_SOFT_ERROR 10.0) + +# https://en.wikipedia.org/wiki/Microsoft_Visual_C#Internal_version_numbering +# _MSC_VER == 1928 MSVC++ 19.27 Visual Studio 2019 Version 16.8 + 16.9 +set(MSVC_MIN 19.28) +set(MSVC_SOFT_ERROR 19.28) + +set(LIBSTDCXX_MIN 7) +set(LIBSTDCXX_SOFT_ERROR 7) + + +if(DEFINED RCC_COMPILER_CHECKED) + return() +endif() +set(RCC_COMPILER_CHECKED ON) + +if(RCC_FORCE_USE_OLD_TOOLCHAIN) + return() +endif() + +function(check_compiler_version NAME NICE_NAME MINIMUM_VERSION SOFT_ERROR_VERSION) + if(NOT CMAKE_CXX_COMPILER_ID STREQUAL NAME) + return() + endif() + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS MINIMUM_VERSION) + message(FATAL_ERROR "Host ${NICE_NAME} version must be at least ${MINIMUM_VERSION}, your version is ${CMAKE_CXX_COMPILER_VERSION}.") + elseif(CMAKE_CXX_COMPILER_VERSION VERSION_LESS SOFT_ERROR_VERSION) + if(RCC_TEMPORARILY_ALLOW_OLD_TOOLCHAIN) + message(WARNING "Host ${NICE_NAME} version should be at least ${SOFT_ERROR_VERSION} because RCC will soon use new C++ features which your toolchain version doesn't support. Your version is ${CMAKE_CXX_COMPILER_VERSION}. Ignoring because you've set RCC_TEMPORARILY_ALLOW_OLD_TOOLCHAIN, but very soon your toolchain won't be supported.") + else() + message(FATAL_ERROR "Host ${NICE_NAME} version should be at least ${SOFT_ERROR_VERSION} because RCC will soon use new C++ features which your toolchain version doesn't support. Your version is ${CMAKE_CXX_COMPILER_VERSION}. You can temporarily opt out using RCC_TEMPORARILY_ALLOW_OLD_TOOLCHAIN, but very soon your toolchain won't be supported.") + endif() + endif() +endfunction(check_compiler_version) + +check_compiler_version("GNU" "GCC" ${GCC_MIN} ${GCC_SOFT_ERROR}) +check_compiler_version("Clang" "Clang" ${CLANG_MIN} ${CLANG_SOFT_ERROR}) +check_compiler_version("AppleClang" "Apple Clang" ${APPLECLANG_MIN} ${APPLECLANG_SOFT_ERROR}) +check_compiler_version("MSVC" "Visual Studio" ${MSVC_MIN} ${MSVC_SOFT_ERROR}) + +# See https://developercommunity.visualstudio.com/content/problem/845933/miscompile-boolean-condition-deduced-to-be-always.html +# and thread "[rcc-dev] Longstanding failing tests - clang-tidy, MachO, Polly" +# on rcc-dev Jan 21-23 2020. +if ((${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC) AND + (19.24 VERSION_LESS_EQUAL ${CMAKE_CXX_COMPILER_VERSION}) AND + (${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 19.25)) + if(RCC_TEMPORARILY_ALLOW_OLD_TOOLCHAIN) + message(WARNING "Host Visual Studio version 16.4 is known to miscompile part of RCC") + else() + message(FATAL_ERROR "Host Visual Studio version 16.4 is known to miscompile part of RCC, please use clang-cl or upgrade to 16.5 or above (use -DRCC_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON to ignore)") + endif() +endif() + + +if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + if (CMAKE_CXX_SIMULATE_ID MATCHES "MSVC") + if (CMAKE_CXX_SIMULATE_VERSION VERSION_LESS MSVC_MIN) + message(FATAL_ERROR "Host Clang must have at least -fms-compatibility-version=${MSVC_MIN}, your version is ${CMAKE_CXX_SIMULATE_VERSION}.") + endif() + set(CLANG_CL 1) + elseif(NOT RCC_ENABLE_LIBCXX) + # Test that we aren't using too old of a version of libstdc++. + set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) + set(OLD_CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++0x") + check_cxx_source_compiles(" +#include <iosfwd> +#if defined(__GLIBCXX__) +#if !defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE < ${LIBSTDCXX_MIN} +#error Unsupported libstdc++ version +#endif +#endif +int main() { return 0; } +" + RCC_LIBSTDCXX_MIN) + if(NOT RCC_LIBSTDCXX_MIN) + message(FATAL_ERROR "libstdc++ version must be at least ${GCC_MIN}.") + endif() + check_cxx_source_compiles(" +#include <iosfwd> +#if defined(__GLIBCXX__) +#if !defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE < ${LIBSTDCXX_SOFT_ERROR} +#error Unsupported libstdc++ version +#endif +#endif +int main() { return 0; } +" + RCC_LIBSTDCXX_SOFT_ERROR) + if(NOT RCC_LIBSTDCXX_SOFT_ERROR) + if(RCC_TEMPORARILY_ALLOW_OLD_TOOLCHAIN) + message(WARNING "libstdc++ version should be at least ${LIBSTDCXX_SOFT_ERROR} because RCC will soon use new C++ features which your toolchain version doesn't support. Ignoring because you've set RCC_TEMPORARILY_ALLOW_OLD_TOOLCHAIN, but very soon your toolchain won't be supported.") + else() + message(FATAL_ERROR "libstdc++ version should be at least ${LIBSTDCXX_SOFT_ERROR} because RCC will soon use new C++ features which your toolchain version doesn't support. You can temporarily opt out using RCC_TEMPORARILY_ALLOW_OLD_TOOLCHAIN, but very soon your toolchain won't be supported.") + endif() + endif() + set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS}) + set(CMAKE_REQUIRED_LIBRARIES ${OLD_CMAKE_REQUIRED_LIBRARIES}) + endif() +endif() diff --git a/rcc/cmake/modules/CheckProblematicConfigurations.cmake b/rcc/cmake/modules/CheckProblematicConfigurations.cmake new file mode 100644 index 0000000..3b96db9 --- /dev/null +++ b/rcc/cmake/modules/CheckProblematicConfigurations.cmake @@ -0,0 +1,19 @@ + +option(RCC_ALLOW_PROBLEMATIC_CONFIGURATIONS OFF "Set this option to ON to allow problematic toolchain configurations. Use on your own risk.") + +macro(log_problematic MESSAGE) + if(RCC_ALLOW_PROBLEMATIC_CONFIGURATIONS) + message(WARNING "${MESSAGE}") + else() + message(FATAL_ERROR "${MESSAGE}\nYou can force usage of this configuration by passing -DRCC_ALLOW_PROBLEMATIC_CONFIGURATIONS=ON") + endif() +endmacro() + +# MSVC and /arch:AVX is untested and have created problems before. See: +# https://github.com/rcc/rcc-project/issues/54645 +if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + string(TOLOWER "${CMAKE_CXX_FLAGS} ${CMAKE_C_FLAGS}" _FLAGS) + if(_FLAGS MATCHES "/arch:avx[0-9]*") + log_problematic("Compiling RCC with MSVC and the /arch:AVX flag is known to cause issues with parts of RCC.\nSee https://github.com/rcc/rcc-project/issues/54645 for details.\nUse clang-cl if you want to enable AVX instructions.") + endif() +endif() diff --git a/rcc/cmake/modules/DetermineGCCCompatible.cmake b/rcc/cmake/modules/DetermineGCCCompatible.cmake new file mode 100644 index 0000000..b645e45 --- /dev/null +++ b/rcc/cmake/modules/DetermineGCCCompatible.cmake @@ -0,0 +1,13 @@ +# Determine if the compiler has GCC-compatible command-line syntax. + +if(NOT DEFINED RCC_COMPILER_IS_GCC_COMPATIBLE) + if(CMAKE_COMPILER_IS_GNUCXX) + set(RCC_COMPILER_IS_GCC_COMPATIBLE ON) + elseif( MSVC ) + set(RCC_COMPILER_IS_GCC_COMPATIBLE OFF) + elseif( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) + set(RCC_COMPILER_IS_GCC_COMPATIBLE ON) + elseif( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Intel" ) + set(RCC_COMPILER_IS_GCC_COMPATIBLE ON) + endif() +endif() diff --git a/rcc/cmake/modules/FindFFI.cmake b/rcc/cmake/modules/FindFFI.cmake new file mode 100644 index 0000000..b1f6452 --- /dev/null +++ b/rcc/cmake/modules/FindFFI.cmake @@ -0,0 +1,106 @@ +# Attempts to discover ffi library with a linkable ffi_call function. +# +# Example usage: +# +# find_package(FFI) +# +# FFI_REQUIRE_INCLUDE may be set to consider ffi found if the includes +# are present in addition to the library. This is useful to keep off +# for the imported package on platforms that install the library but +# not the headers. +# +# FFI_LIBRARY_DIR may be set to define search paths for the ffi library. +# +# If successful, the following variables will be defined: +# FFI_FOUND +# FFI_INCLUDE_DIRS +# FFI_LIBRARIES +# FFI_STATIC_LIBRARIES +# HAVE_FFI_CALL +# +# HAVE_FFI_H or HAVE_FFI_FFI_H is defined depending on the ffi.h include path. +# +# Additionally, the following import target will be defined: +# FFI::ffi + +find_package(PkgConfig QUIET) +pkg_check_modules(PC_LIBFFI QUIET libffi) + +find_path(FFI_INCLUDE_DIRS ffi.h PATHS ${FFI_INCLUDE_DIR} ${PC_LIBFFI_INCLUDE_DIRS}) +if( EXISTS "${FFI_INCLUDE_DIRS}/ffi.h" ) + set(FFI_HEADER ffi.h CACHE INTERNAL "") + set(HAVE_FFI_H 1 CACHE INTERNAL "") +else() + find_path(FFI_INCLUDE_DIRS ffi/ffi.h PATHS ${FFI_INCLUDE_DIR}) + if( EXISTS "${FFI_INCLUDE_DIRS}/ffi/ffi.h" ) + set(FFI_HEADER ffi/ffi.h CACHE INTERNAL "") + set(HAVE_FFI_FFI_H 1 CACHE INTERNAL "") + endif() +endif() + +find_library(FFI_LIBRARIES NAMES ffi PATHS ${FFI_LIBRARY_DIR} ${PC_LIBFFI_LIBRARY_DIRS}) +find_library(FFI_STATIC_LIBRARIES NAMES libffi.a PATHS ${FFI_LIBRARY_DIR} ${PC_LIBFFI_LIBRARY_DIRS}) + +if(FFI_LIBRARIES) + include(CMakePushCheckState) + cmake_push_check_state() + list(APPEND CMAKE_REQUIRED_LIBRARIES ${FFI_LIBRARIES}) + set(HAVE_FFI_CALL_SRC [=[ + #ifdef __cplusplus + extern "C" { + #endif + struct ffi_cif; + typedef struct ffi_cif ffi_cif; + void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue); + #ifdef __cplusplus + } + #endif + int main(void) { ffi_call(0, 0, 0, 0); } + ]=]) + if(DEFINED CMAKE_C_COMPILER) + include(CheckCSourceCompiles) + check_c_source_compiles("${HAVE_FFI_CALL_SRC}" HAVE_FFI_CALL) + else() + include(CheckCXXSourceCompiles) + check_cxx_source_compiles("${HAVE_FFI_CALL_SRC}" HAVE_FFI_CALL) + endif() + cmake_pop_check_state() +endif() + +unset(required_includes) +if(FFI_REQUIRE_INCLUDE) + set(required_includes FFI_INCLUDE_DIRS) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(FFI + FOUND_VAR + FFI_FOUND + REQUIRED_VARS + FFI_LIBRARIES + ${required_includes} + HAVE_FFI_CALL) +mark_as_advanced(FFI_LIBRARIES + FFI_STATIC_LIBRARIES + FFI_INCLUDE_DIRS + HAVE_FFI_CALL + FFI_HEADER + HAVE_FFI_H + HAVE_FFI_FFI_H) + +if(FFI_FOUND) + if(NOT TARGET FFI::ffi AND FFI_LIBRARIES) + add_library(FFI::ffi UNKNOWN IMPORTED) + set_target_properties(FFI::ffi PROPERTIES IMPORTED_LOCATION "${FFI_LIBRARIES}") + if(FFI_INCLUDE_DIRS) + set_target_properties(FFI::ffi PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFI_INCLUDE_DIRS}") + endif() + endif() + if(NOT TARGET FFI::ffi_static AND FFI_STATIC_LIBRARIES) + add_library(FFI::ffi_static UNKNOWN IMPORTED) + set_target_properties(FFI::ffi_static PROPERTIES IMPORTED_LOCATION "${FFI_STATIC_LIBRARIES}") + if(FFI_INCLUDE_DIRS) + set_target_properties(FFI::ffi_static PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFI_INCLUDE_DIRS}") + endif() + endif() +endif() diff --git a/rcc/cmake/modules/FindLibEdit.cmake b/rcc/cmake/modules/FindLibEdit.cmake new file mode 100644 index 0000000..b3f49e1 --- /dev/null +++ b/rcc/cmake/modules/FindLibEdit.cmake @@ -0,0 +1,65 @@ +#.rst: +# FindLibEdit +# ----------- +# +# Find libedit library and headers +# +# The module defines the following variables: +# +# :: +# +# LibEdit_FOUND - true if libedit was found +# LibEdit_INCLUDE_DIRS - include search path +# LibEdit_LIBRARIES - libraries to link +# LibEdit_VERSION_STRING - version number + +find_package(PkgConfig QUIET) +pkg_check_modules(PC_LIBEDIT QUIET libedit) + +find_path(LibEdit_INCLUDE_DIRS NAMES histedit.h HINTS ${PC_LIBEDIT_INCLUDE_DIRS}) +find_library(LibEdit_LIBRARIES NAMES edit HINTS ${PC_LIBEDIT_LIBRARY_DIRS}) + +include(CheckIncludeFile) +if(LibEdit_INCLUDE_DIRS AND EXISTS "${LibEdit_INCLUDE_DIRS}/histedit.h") + include(CMakePushCheckState) + cmake_push_check_state() + list(APPEND CMAKE_REQUIRED_INCLUDES ${LibEdit_INCLUDE_DIRS}) + list(APPEND CMAKE_REQUIRED_LIBRARIES ${LibEdit_LIBRARIES}) + check_include_file(histedit.h HAVE_HISTEDIT_H) + cmake_pop_check_state() + if (HAVE_HISTEDIT_H) + file(STRINGS "${LibEdit_INCLUDE_DIRS}/histedit.h" + libedit_major_version_str + REGEX "^#define[ \t]+LIBEDIT_MAJOR[ \t]+[0-9]+") + string(REGEX REPLACE "^#define[ \t]+LIBEDIT_MAJOR[ \t]+([0-9]+)" "\\1" + libedit_major_version "${libedit_major_version_str}") + + file(STRINGS "${LibEdit_INCLUDE_DIRS}/histedit.h" + libedit_minor_version_str + REGEX "^#define[ \t]+LIBEDIT_MINOR[ \t]+[0-9]+") + string(REGEX REPLACE "^#define[ \t]+LIBEDIT_MINOR[ \t]+([0-9]+)" "\\1" + libedit_minor_version "${libedit_minor_version_str}") + + set(LibEdit_VERSION_STRING "${libedit_major_version}.${libedit_minor_version}") + else() + set(LibEdit_INCLUDE_DIRS "") + set(LibEdit_LIBRARIES "") + endif() +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(LibEdit + FOUND_VAR + LibEdit_FOUND + REQUIRED_VARS + LibEdit_INCLUDE_DIRS + LibEdit_LIBRARIES + VERSION_VAR + LibEdit_VERSION_STRING) +mark_as_advanced(LibEdit_INCLUDE_DIRS LibEdit_LIBRARIES) + +if (LibEdit_FOUND AND NOT TARGET LibEdit::LibEdit) + add_library(LibEdit::LibEdit INTERFACE IMPORTED) + target_link_libraries(LibEdit::LibEdit INTERFACE ${LibEdit_LIBRARIES}) + target_include_directories(LibEdit::LibEdit INTERFACE ${LibEdit_INCLUDE_DIRS}) +endif() diff --git a/rcc/cmake/modules/FindLibpfm.cmake b/rcc/cmake/modules/FindLibpfm.cmake new file mode 100644 index 0000000..9e5900b --- /dev/null +++ b/rcc/cmake/modules/FindLibpfm.cmake @@ -0,0 +1,37 @@ +# CMake module for finding libpfm4. +# +# If successful, the following variables will be defined: +# HAVE_LIBPFM +# +# Libpfm can be disabled by setting RCC_ENABLE_LIBPFM to 0. + +include(CheckIncludeFile) +include(CheckLibraryExists) +include(CheckCXXSourceCompiles) + +if (RCC_ENABLE_LIBPFM) + check_library_exists(pfm pfm_initialize "" HAVE_LIBPFM_INITIALIZE) + if(HAVE_LIBPFM_INITIALIZE) + check_include_file(perfmon/perf_event.h HAVE_PERFMON_PERF_EVENT_H) + check_include_file(perfmon/pfmlib.h HAVE_PERFMON_PFMLIB_H) + check_include_file(perfmon/pfmlib_perf_event.h HAVE_PERFMON_PFMLIB_PERF_EVENT_H) + if(HAVE_PERFMON_PERF_EVENT_H AND HAVE_PERFMON_PFMLIB_H AND HAVE_PERFMON_PFMLIB_PERF_EVENT_H) + set(HAVE_LIBPFM 1) + # Check to see if perf_branch_entry has the field 'cycles'. + # We couldn't use CheckStructHasMember here because 'cycles' is a bit field which is not + # supported by CheckStructHasMember. + CHECK_CXX_SOURCE_COMPILES(" + #include <perfmon/perf_event.h> + int main() { + perf_branch_entry entry; + entry.cycles = 2; + return 0; + }" COMPILE_WITH_CYCLES) + if(COMPILE_WITH_CYCLES) + set(LIBPFM_HAS_FIELD_CYCLES 1) + endif() + endif() + endif() +endif() + + diff --git a/rcc/cmake/modules/FindOCaml.cmake b/rcc/cmake/modules/FindOCaml.cmake new file mode 100644 index 0000000..8eba212 --- /dev/null +++ b/rcc/cmake/modules/FindOCaml.cmake @@ -0,0 +1,103 @@ +# CMake find_package() module for the OCaml language. +# Assumes ocamlfind will be used for compilation. +# http://ocaml.org/ +# +# Example usage: +# +# find_package(OCaml) +# +# If successful, the following variables will be defined: +# OCAMLFIND +# OCAML_VERSION +# OCAML_STDLIB_PATH +# HAVE_OCAMLOPT +# +# Also provides find_ocamlfind_package() macro. +# +# Example usage: +# +# find_ocamlfind_package(ctypes) +# +# In any case, the following variables are defined: +# +# HAVE_OCAML_${pkg} +# +# If successful, the following variables will be defined: +# +# OCAML_${pkg}_VERSION + +include( FindPackageHandleStandardArgs ) + +find_program(OCAMLFIND + NAMES ocamlfind) + +if( OCAMLFIND ) + execute_process( + COMMAND ${OCAMLFIND} ocamlc -version + OUTPUT_VARIABLE OCAML_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) + + execute_process( + COMMAND ${OCAMLFIND} ocamlc -where + OUTPUT_VARIABLE OCAML_STDLIB_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE) + + execute_process( + COMMAND ${OCAMLFIND} ocamlc -version + OUTPUT_QUIET + RESULT_VARIABLE find_ocaml_result) + if( find_ocaml_result EQUAL 0 ) + set(HAVE_OCAMLOPT TRUE) + else() + set(HAVE_OCAMLOPT FALSE) + endif() +endif() + +find_package_handle_standard_args( OCaml DEFAULT_MSG + OCAMLFIND + OCAML_VERSION + OCAML_STDLIB_PATH) + +mark_as_advanced( + OCAMLFIND) + +function(find_ocamlfind_package pkg) + CMAKE_PARSE_ARGUMENTS(ARG "OPTIONAL" "VERSION" "" ${ARGN}) + + execute_process( + COMMAND "${OCAMLFIND}" "query" "${pkg}" "-format" "%v" + RESULT_VARIABLE result + OUTPUT_VARIABLE version + ERROR_VARIABLE error + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_STRIP_TRAILING_WHITESPACE) + + if( NOT result EQUAL 0 AND NOT ARG_OPTIONAL ) + message(FATAL_ERROR ${error}) + endif() + + if( result EQUAL 0 ) + set(found TRUE) + else() + set(found FALSE) + endif() + + if( found AND ARG_VERSION ) + if( version VERSION_LESS ARG_VERSION AND ARG_OPTIONAL ) + # If it's optional and the constraint is not satisfied, pretend + # it wasn't found. + set(found FALSE) + elseif( version VERSION_LESS ARG_VERSION ) + message(FATAL_ERROR + "ocamlfind package ${pkg} should have version ${ARG_VERSION} or newer") + endif() + endif() + + string(TOUPPER ${pkg} pkg) + + set(HAVE_OCAML_${pkg} ${found} + PARENT_SCOPE) + + set(OCAML_${pkg}_VERSION ${version} + PARENT_SCOPE) +endfunction() diff --git a/rcc/cmake/modules/GetErrcMessages.cmake b/rcc/cmake/modules/GetErrcMessages.cmake new file mode 100644 index 0000000..ad94f6a --- /dev/null +++ b/rcc/cmake/modules/GetErrcMessages.cmake @@ -0,0 +1,45 @@ +# This function returns the messages of various POSIX error codes as they are returned by std::error_code. +# The purpose of this function is to supply those error messages to rcc-lit using the errc_messages config. +# Currently supplied and needed error codes: ENOENT, EISDIR, EINVAL and EACCES. +# Messages are semi colon separated. +# Keep amount, order and tested error codes in sync with rcc/utils/lit/lit/rcc/config.py. +function(get_errc_messages outvar) + if(CMAKE_CROSSCOMPILING AND NOT CMAKE_CROSSCOMPILING_EMULATOR AND NOT DEFINED errc_exit_code) + set(${outvar} "" PARENT_SCOPE) + message(STATUS "Can't get errc messages in cross-compilation mode") + return() + endif() + + set(errc_test_code ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/getErrc.cpp) + + file(WRITE ${errc_test_code} " + #include <cerrno> + #include <iostream> + #include <string> + #include <system_error> + + std::string getMessageFor(int err) { + return std::make_error_code(static_cast<std::errc>(err)).message(); + } + + int main() { + std::cout << getMessageFor(ENOENT) << ';' << getMessageFor(EISDIR); + std::cout << ';' << getMessageFor(EINVAL) << ';' << getMessageFor(EACCES); + return 0; + } + ") + + try_run(errc_exit_code + errc_compiled + ${CMAKE_BINARY_DIR} + ${errc_test_code} + RUN_OUTPUT_VARIABLE errc_result + COMPILE_OUTPUT_VARIABLE errc_compile_errors) + if (errc_compiled AND "${errc_exit_code}" STREQUAL "0") + set(${outvar} ${errc_result} PARENT_SCOPE) + else() + set(${outvar} "" PARENT_SCOPE) + message(NOTICE "${errc_compile_errors}") + message(STATUS "Failed to get errc messages") + endif () +endfunction() diff --git a/rcc/cmake/modules/GetHostTriple.cmake b/rcc/cmake/modules/GetHostTriple.cmake new file mode 100644 index 0000000..046fc36 --- /dev/null +++ b/rcc/cmake/modules/GetHostTriple.cmake @@ -0,0 +1,98 @@ +# Returns the host triple. +# Invokes config.guess, except for platforms it cannot identify. + +function( get_host_triple var ) + if( MSVC OR CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC") + if( CMAKE_C_COMPILER_ARCHITECTURE_ID MATCHES "ARM64.*" ) + set( value "aarch64-pc-windows-msvc" ) + elseif( CMAKE_C_COMPILER_ARCHITECTURE_ID MATCHES "ARM.*" ) + set( value "armv7-pc-windows-msvc" ) + elseif( CMAKE_C_COMPILER_ARCHITECTURE_ID STREQUAL "x64" ) + set( value "x86_64-pc-windows-msvc" ) + elseif( CMAKE_C_COMPILER_ARCHITECTURE_ID STREQUAL "X86" ) + set( value "i686-pc-windows-msvc" ) + elseif( CMAKE_SIZEOF_VOID_P EQUAL 8 ) + set( value "x86_64-pc-windows-msvc" ) + else() + set( value "i686-pc-windows-msvc" ) + endif() + elseif( MINGW AND NOT MSYS ) + # CMake doesn't provide COMPILER_ARCHITECTURE_ID for Clang/GCC, + # but it does for MSVC. + if( CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "ARM.*" ) + if( CMAKE_SIZEOF_VOID_P EQUAL 8 ) + set( value "aarch64-w64-windows-gnu" ) + else() + set( value "armv7-w64-windows-gnu" ) + endif() + else() + if( CMAKE_SIZEOF_VOID_P EQUAL 8 ) + set( value "x86_64-w64-windows-gnu" ) + else() + set( value "i686-w64-windows-gnu" ) + endif() + endif() + elseif( CMAKE_SYSTEM_NAME MATCHES "OS390" ) + set( value "s390x-ibm-zos" ) + elseif( CMAKE_SYSTEM_NAME STREQUAL "AIX" ) + # We defer to dynamic detection of the host AIX version. + if( CMAKE_SIZEOF_VOID_P EQUAL 8 ) + set( value "powerpc64-ibm-aix" ) + else() + set( value "powerpc-ibm-aix" ) + endif() + elseif( CMAKE_HOST_SYSTEM_NAME MATCHES "HarmonyOS|OpenHarmony|OHOS" ) + # config.guess cannot identify HarmonyOS: uname -s reports "HarmonyOS", + # which config.guess does not recognize, and its probing is rejected by + # the system sandbox. Build the triple from CMake's host detection using + # the form clang targets on OHOS (e.g. aarch64-unknown-linux-ohos). CMake + # itself may report the host processor as "unknown" because uname -p does, + # so fall back to asking uname -m directly. + set( TT_MACHINE "${CMAKE_HOST_SYSTEM_PROCESSOR}" ) + if( NOT TT_MACHINE OR TT_MACHINE STREQUAL "unknown" ) + find_program( TT_UNAME uname PATHS /bin /usr/bin /usr/local/bin + NO_CMAKE_FIND_ROOT_PATH ) + set( TT_RV 1 ) + if( TT_UNAME ) + execute_process( COMMAND ${TT_UNAME} -m + RESULT_VARIABLE TT_RV + OUTPUT_VARIABLE TT_MACHINE + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET ) + endif() + if( NOT TT_RV EQUAL 0 ) + set( TT_MACHINE "" ) + endif() + endif() + if( TT_MACHINE MATCHES "aarch64|arm64" ) + set( value "aarch64-unknown-linux-ohos" ) + elseif( TT_MACHINE MATCHES "^arm" ) + set( value "arm-unknown-linux-ohos" ) + elseif( TT_MACHINE MATCHES "^x86_64" ) + set( value "x86_64-unknown-linux-ohos" ) + elseif( TT_MACHINE MATCHES "^riscv64" ) + set( value "riscv64-unknown-linux-ohos" ) + elseif( TT_MACHINE MATCHES "^loongarch64" ) + set( value "loongarch64-unknown-linux-ohos" ) + else() + message( FATAL_ERROR + "Failed to determine host triple for ${CMAKE_HOST_SYSTEM_NAME}: " + "host processor \"${TT_MACHINE}\" is not supported" ) + endif() + else() + if(CMAKE_HOST_SYSTEM_NAME STREQUAL Windows AND NOT MSYS) + message(WARNING "unable to determine host target triple") + else() + set(config_guess ${RCC_MAIN_SRC_DIR}/cmake/config.guess) + execute_process(COMMAND sh ${config_guess} + RESULT_VARIABLE TT_RV + OUTPUT_VARIABLE TT_OUT + OUTPUT_STRIP_TRAILING_WHITESPACE) + if( NOT TT_RV EQUAL 0 ) + message(FATAL_ERROR "Failed to execute ${config_guess}") + endif( NOT TT_RV EQUAL 0 ) + set( value ${TT_OUT} ) + endif() + endif() + set( ${var} ${value} PARENT_SCOPE ) +endfunction( get_host_triple var ) diff --git a/rcc/cmake/modules/HandleRCCOptions.cmake b/rcc/cmake/modules/HandleRCCOptions.cmake new file mode 100644 index 0000000..6b99829 --- /dev/null +++ b/rcc/cmake/modules/HandleRCCOptions.cmake @@ -0,0 +1,1182 @@ +# SPDX-License-Identifier: GPL-3.0-or-later + +include_guard(GLOBAL) + +include(CheckCCompilerFlag) +include(CheckCSourceCompiles) +include(CheckCXXCompilerFlag) +include(CheckCXXSourceCompiles) +include(CMakePushCheckState) +include(CheckLinkerFlag) +include(CheckSymbolExists) + +function(rcc_append_flags value) + foreach(variable IN LISTS ARGN) + set(${variable} "${${variable}} ${value}" PARENT_SCOPE) + endforeach() +endfunction() + +macro(rcc_add_supported_warning flag name) + check_c_compiler_flag("-Werror ${flag}" RCC_C_SUPPORTS_${name}) + if(RCC_C_SUPPORTS_${name}) + rcc_append_flags("${flag}" CMAKE_C_FLAGS) + endif() + check_cxx_compiler_flag("-Werror ${flag}" RCC_CXX_SUPPORTS_${name}) + if(RCC_CXX_SUPPORTS_${name}) + rcc_append_flags("${flag}" CMAKE_CXX_FLAGS) + endif() +endmacro() + +macro(rcc_configure_job_pools) + set(RCC_PARALLEL_COMPILE_JOBS "" CACHE STRING "Maximum concurrent compilation jobs (Ninja only)") + set(RCC_PARALLEL_LINK_JOBS "" CACHE STRING "Maximum concurrent link jobs (Ninja only)") + if(RCC_RAM_PER_COMPILE_JOB OR RCC_RAM_PER_LINK_JOB) + cmake_host_system_information(RESULT rccAvailableMemory QUERY AVAILABLE_PHYSICAL_MEMORY) + cmake_host_system_information(RESULT rccLogicalCores QUERY NUMBER_OF_LOGICAL_CORES) + endif() + foreach(rccJobKind COMPILE LINK) + if(RCC_RAM_PER_${rccJobKind}_JOB) + math(EXPR rccMemoryJobs "${rccAvailableMemory} / ${RCC_RAM_PER_${rccJobKind}_JOB}" OUTPUT_FORMAT DECIMAL) + if(rccMemoryJobs LESS 1) + set(rccMemoryJobs 1) + endif() + if(rccMemoryJobs LESS rccLogicalCores) + set(RCC_PARALLEL_${rccJobKind}_JOBS "${rccMemoryJobs}") + else() + set(RCC_PARALLEL_${rccJobKind}_JOBS "${rccLogicalCores}") + endif() + endif() + endforeach() + if(RCC_PARALLEL_COMPILE_JOBS) + if(CMAKE_GENERATOR MATCHES "Ninja") + set_property(GLOBAL APPEND PROPERTY JOB_POOLS compile_job_pool=${RCC_PARALLEL_COMPILE_JOBS}) + set(CMAKE_JOB_POOL_COMPILE compile_job_pool) + else() + message(WARNING "Job pooling is only available with Ninja generators.") + endif() + endif() + if(CMAKE_GENERATOR MATCHES "Ninja") + if(NOT RCC_PARALLEL_LINK_JOBS AND rccLTOMode STREQUAL "THIN") + message(STATUS "ThinLTO provides its own parallel linking - limiting parallel link jobs to 2.") + set(RCC_PARALLEL_LINK_JOBS 2) + endif() + if(RCC_PARALLEL_LINK_JOBS) + set_property(GLOBAL APPEND PROPERTY JOB_POOLS link_job_pool=${RCC_PARALLEL_LINK_JOBS}) + set(CMAKE_JOB_POOL_LINK link_job_pool) + endif() + elseif(RCC_PARALLEL_LINK_JOBS) + message(WARNING "Job pooling is only available with Ninja generators.") + endif() +endmacro() + +macro(rcc_configure_platform_checks) + if(UNIX AND CMAKE_SYSTEM_NAME MATCHES "AIX") + list(APPEND CMAKE_REQUIRED_DEFINITIONS "-D_XOPEN_SOURCE=700" "-D_LARGE_FILE_API") + endif() + if(UNIX AND CMAKE_SYSTEM_NAME MATCHES "SunOS") + list(APPEND CMAKE_REQUIRED_DEFINITIONS "-D_FILE_OFFSET_BITS=64") + endif() + check_symbol_exists(__GLIBC__ stdio.h RCC_USING_GLIBC) + if(RCC_USING_GLIBC OR CYGWIN) + add_compile_definitions(_GNU_SOURCE) + list(APPEND CMAKE_REQUIRED_DEFINITIONS "-D_GNU_SOURCE") + endif() + if(RCC_USING_GLIBC AND CMAKE_SIZEOF_VOID_P EQUAL 4) + add_compile_definitions(_FILE_OFFSET_BITS=64) + list(APPEND CMAKE_REQUIRED_DEFINITIONS "-D_FILE_OFFSET_BITS=64") + endif() + if(NOT RCC_ENABLE_PIC) + rcc_append_flags("-fno-pie" CMAKE_EXE_LINKER_FLAGS) + endif() +endmacro() + +macro(rcc_configure_platform_link_options) + if(APPLE) + rcc_append_flags("-Wl,-flat_namespace -Wl,-undefined -Wl,dynamic_lookup" CMAKE_MODULE_LINKER_FLAGS) + endif() + if(CMAKE_SYSTEM_NAME MATCHES "AIX") + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + rcc_append_flags("-mcmodel=large" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + rcc_append_flags("-Wl,-bglink=large" CMAKE_EXE_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) + elseif(CMAKE_CXX_COMPILER_ID MATCHES "XL") + rcc_append_flags("-Wl,-bbigtoc -bcdtors:mbr" + CMAKE_EXE_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) + endif() + if(BUILD_SHARED_LIBS) + message(WARNING "Build and install environment path info may be exposed; binaries will also be unrelocatable.") + endif() + endif() + if(CMAKE_SYSTEM_NAME MATCHES "OS390") + rcc_append_flags("-Wl,-bcompress=yes" CMAKE_EXE_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) + endif() + if(NOT (CMAKE_SYSTEM_NAME MATCHES "Darwin|FreeBSD|OpenBSD|DragonFly|AIX|OS390|Emscripten" + OR WIN32 OR CYGWIN) AND NOT RCC_USE_SANITIZER) + rcc_append_flags("-Wl,-z,defs" CMAKE_SHARED_LINKER_FLAGS) + endif() +endmacro() + +macro(rcc_configure_platform_definitions) + if(UNIX AND CMAKE_SYSTEM_NAME MATCHES "AIX") + add_compile_definitions(_XOPEN_SOURCE=700 _LARGE_FILE_API) + add_compile_options(-pthread) + rcc_append_flags("-shared -Wl,-G" CMAKE_MODULE_LINKER_FLAGS) + rcc_append_flags("-shared" CMAKE_SHARED_LINKER_FLAGS) + endif() + if(CMAKE_SYSTEM_NAME MATCHES "OS390") + add_compile_definitions(_XOPEN_SOURCE=600 _XPLATFORM_SOURCE _OPEN_SYS _OPEN_SYS_FILE_EXT _EXT) + rcc_append_flags("-fzos-le-char-mode=ascii -m64" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + if(UNIX AND CMAKE_SYSTEM_NAME MATCHES "SunOS") + add_compile_definitions(_FILE_OFFSET_BITS=64) + endif() +endmacro() + +macro(rcc_configure_warning_options) + if(MSVC) + if(RCC_ENABLE_WERROR) + rcc_append_flags("/WX" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + if(RCC_ENABLE_WARNINGS) + string(REGEX REPLACE " /W[0-4]" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") + string(REGEX REPLACE " /W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + rcc_append_flags("/W4" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + if(NOT RCC_CLANG_CL) + if(RCC_ENABLE_WARNING_SUPPRESSIONS) + rcc_append_flags( + "-wd4146 -wd4244 -wd4267 -wd4456 -wd4457 -wd4458 -wd4459 -wd4624 -wd4100 -wd4127 -wd4505 -wd4702 -wd4245 -wd4310 -wd4701 -wd4703 -wd4389 -wd4805 -wd4577 -wd4319 -wd4324 -wd4251 -wd4275" + CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + rcc_append_flags("-w14062 -we4238" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + endif() + + if(RCC_GCC_COMPATIBLE AND RCC_ENABLE_WERROR) + rcc_append_flags("-Werror" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + rcc_append_flags("-Wno-error" CMAKE_REQUIRED_FLAGS) + endif() + if(RCC_GCC_COMPATIBLE OR CMAKE_CXX_COMPILER_ID MATCHES "XL") + rcc_append_flags("-Werror=date-time" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + rcc_append_flags("-Werror=unguarded-availability-new" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + + set(rccInitialCFlags "${CMAKE_C_FLAGS}") + set(rccInitialCXXFlags "${CMAKE_CXX_FLAGS}") + if(RCC_ENABLE_WARNINGS AND (RCC_GCC_COMPATIBLE OR RCC_CLANG_CL)) + if(NOT RCC_CLANG_CL) + rcc_append_flags("-Wall" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + rcc_append_flags("-Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual" + CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + rcc_append_flags("-Wno-missing-field-initializers" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + else() + rcc_append_flags("-Wmissing-field-initializers" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + + if(RCC_ENABLE_PEDANTIC AND RCC_GCC_COMPATIBLE) + rcc_append_flags("-pedantic -Wno-long-long" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + rcc_add_supported_warning("-Wc++98-compat-extra-semi" CXX98_COMPAT_EXTRA_SEMI) + endif() + rcc_append_flags("-Wimplicit-fallthrough" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + rcc_append_flags("-Wcovered-switch-default" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + # Match LLVM's GCC warning suppression policy and version conditions. + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.0) + rcc_append_flags("-Wno-uninitialized" CMAKE_CXX_FLAGS) + else() + rcc_append_flags("-Wno-maybe-uninitialized" CMAKE_CXX_FLAGS) + endif() + rcc_append_flags("-Wno-nonnull" CMAKE_CXX_FLAGS) + if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.1) + rcc_append_flags("-Wno-class-memaccess" CMAKE_CXX_FLAGS) + endif() + if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13.1) + rcc_append_flags("-Wno-dangling-reference" CMAKE_CXX_FLAGS) + endif() + if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 9.1) + rcc_append_flags("-Wno-redundant-move -Wno-pessimizing-move" CMAKE_CXX_FLAGS) + endif() + rcc_append_flags("-Wno-array-bounds" CMAKE_CXX_FLAGS) + if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 11.1) + rcc_append_flags("-Wno-stringop-overread" CMAKE_CXX_FLAGS) + endif() + if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 12.1) + rcc_append_flags("-Wno-dangling-pointer" CMAKE_CXX_FLAGS) + endif() + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 14.0) + rcc_append_flags("-Wno-unused-but-set-parameter" CMAKE_CXX_FLAGS) + endif() + endif() + rcc_append_flags("-Wno-noexcept-type" CMAKE_CXX_FLAGS) + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + rcc_append_flags("-Wnon-virtual-dtor" CMAKE_CXX_FLAGS) + endif() + rcc_append_flags("-Wdelete-non-virtual-dtor" CMAKE_CXX_FLAGS) + + check_cxx_compiler_flag("-Wsuggest-override" RCC_SUPPORTS_SUGGEST_OVERRIDE) + if(RCC_SUPPORTS_SUGGEST_OVERRIDE) + cmake_push_check_state() + string(APPEND CMAKE_REQUIRED_FLAGS " -Werror=suggest-override") + check_cxx_source_compiles([=[ + class Base { public: virtual void anchor(); }; + class Derived : Base { public: void anchor() final; }; + int main() { return 0; } + ]=] RCC_SUGGEST_OVERRIDE_ACCEPTS_FINAL) + cmake_pop_check_state() + if(RCC_SUGGEST_OVERRIDE_ACCEPTS_FINAL) + rcc_append_flags("-Wsuggest-override" CMAKE_CXX_FLAGS) + endif() + endif() + + cmake_push_check_state() + string(APPEND CMAKE_REQUIRED_FLAGS " -Werror -Wcomment") + check_c_source_compiles("// \\\\\\n//\\nint main(void) { return 0; }" + RCC_C_WCOMMENT_ACCEPTS_LINE_WRAP) + cmake_pop_check_state() + if(NOT RCC_C_WCOMMENT_ACCEPTS_LINE_WRAP) + rcc_append_flags("-Wno-comment" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + rcc_append_flags("-Wstring-conversion" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + rcc_append_flags("-Wno-pass-failed" CMAKE_CXX_FLAGS) + endif() + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + rcc_append_flags("-Wno-misleading-indentation" CMAKE_CXX_FLAGS) + else() + rcc_add_supported_warning("-Wmisleading-indentation" MISLEADING_INDENTATION) + endif() + rcc_add_supported_warning("-Wctad-maybe-unsupported" CTAD_MAYBE_UNSUPPORTED) + elseif(RCC_GCC_COMPATIBLE AND NOT RCC_ENABLE_WARNINGS) + rcc_append_flags("-w" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + + if(NOT RCC_ENABLE_WARNING_SUPPRESSIONS AND (RCC_GCC_COMPATIBLE OR RCC_CLANG_CL)) + foreach(rccLanguage C CXX) + string(LENGTH "${rccInitial${rccLanguage}Flags}" rccInitialLength) + string(SUBSTRING "${CMAKE_${rccLanguage}_FLAGS}" ${rccInitialLength} -1 rccAddedFlags) + string(REGEX REPLACE "(^| +)-Wno-[a-zA-Z0-9_-]+" "" rccAddedFlags "${rccAddedFlags}") + set(CMAKE_${rccLanguage}_FLAGS "${rccInitial${rccLanguage}Flags}${rccAddedFlags}") + endforeach() + endif() +endmacro() + +# Configure in the caller's directory scope, as LLVM's option modules do. +macro(rcc_configure_options) + if(DEFINED CMAKE_CXX_STANDARD AND CMAKE_CXX_STANDARD LESS 23) + message(FATAL_ERROR "RCC requires CMAKE_CXX_STANDARD to be at least 23") + endif() + set(CMAKE_CXX_STANDARD 23 CACHE STRING "C++ standard to conform to") + set(CMAKE_CXX_STANDARD_REQUIRED YES) + set(CMAKE_CXX_EXTENSIONS NO) + + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(WARNING "No build type selected. Defaulted CMAKE_BUILD_TYPE=Release.") + set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type: Debug, Release, RelWithDebInfo, MinSizeRel" FORCE) + endif() + if(CMAKE_DEFAULT_BUILD_TYPE) + set(CMAKE_TRY_COMPILE_CONFIGURATION "${CMAKE_DEFAULT_BUILD_TYPE}") + elseif(CMAKE_CONFIGURATION_TYPES) + list(GET CMAKE_CONFIGURATION_TYPES 0 CMAKE_TRY_COMPILE_CONFIGURATION) + elseif(CMAKE_BUILD_TYPE) + set(CMAKE_TRY_COMPILE_CONFIGURATION "${CMAKE_BUILD_TYPE}") + endif() + set(RCC_ADDITIONAL_BUILD_TYPES "" CACHE STRING "Additional allowed CMake build types") + set(rccAllowedBuildTypes DEBUG RELEASE RELWITHDEBINFO MINSIZEREL ${RCC_ADDITIONAL_BUILD_TYPES}) + string(REPLACE ";" "|" rccAllowedBuildTypes "${rccAllowedBuildTypes}") + string(TOUPPER "${rccAllowedBuildTypes}" rccAllowedBuildTypes) + set(assertionsDefault OFF) + string(TOUPPER "${CMAKE_BUILD_TYPE}" buildType) + if(CMAKE_BUILD_TYPE AND NOT buildType MATCHES "^(${rccAllowedBuildTypes})$") + message(FATAL_ERROR "Unknown value for CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") + endif() + if(buildType STREQUAL "DEBUG") + set(assertionsDefault ON) + endif() + option(RCC_ENABLE_WARNINGS "Enable compiler warnings" ON) + option(RCC_ENABLE_WARNING_SUPPRESSIONS "Suppress compiler warnings" ON) + option(RCC_ENABLE_PEDANTIC "Compile with pedantic enabled" ON) + option(RCC_ENABLE_WERROR "Treat compiler warnings as errors" OFF) + option(RCC_ENABLE_ASSERTIONS "Enable assertions" "${assertionsDefault}") + option(RCC_ENABLE_EH "Enable C++ exceptions" OFF) + option(RCC_ENABLE_RTTI "Enable C++ runtime type information" OFF) + option(RCC_ENABLE_UNWIND_TABLES "Emit unwind tables for the libraries" ON) + set(RCC_USE_SANITIZER "" CACHE STRING + "Sanitizer used to build binaries; use LLVM's platform-specific combinations") + option(RCC_OPTIMIZE_SANITIZED_BUILDS "Use -O1 for Debug sanitizer builds" ON) + set(RCC_UBSAN_FLAGS + "-fsanitize=undefined -fno-sanitize=vptr,function -fno-sanitize-recover=all" + CACHE STRING "Compiler flags for the Undefined sanitizer") + + if(RCC_ENABLE_EH AND NOT RCC_ENABLE_RTTI) + message(FATAL_ERROR "RCC_ENABLE_EH requires RCC_ENABLE_RTTI.") + endif() + + if(NOT DEFINED RCC_GCC_COMPATIBLE) + if(CMAKE_COMPILER_IS_GNUCXX) + set(RCC_GCC_COMPATIBLE ON) + elseif(MSVC) + set(RCC_GCC_COMPATIBLE OFF) + elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang|Intel") + set(RCC_GCC_COMPATIBLE ON) + endif() + endif() + set(RCC_CLANG_CL OFF) + if(MSVC AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(RCC_CLANG_CL ON) + endif() + + if(WIN32) + set(RCC_ON_UNIX OFF) + elseif(FUCHSIA OR UNIX OR CYGWIN) + set(RCC_ON_UNIX ON) + elseif(CMAKE_SYSTEM_NAME STREQUAL "Generic") + set(RCC_ON_UNIX OFF) + else() + message(SEND_ERROR "Unable to determine platform") + endif() + + rcc_configure_additional_options() + rcc_configure_standard_library() + rcc_configure_platform_checks() + rcc_configure_job_pools() + + if(RCC_ENABLE_ASSERTIONS) + if(NOT WIN32 OR MINGW) + add_compile_definitions(_DEBUG) + endif() + if(NOT buildType STREQUAL "DEBUG") + add_compile_options("$<$<COMPILE_LANGUAGE:C,CXX>:-UNDEBUG>") + if(MSVC) + foreach(rccFlagsVariable + CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_CXX_FLAGS_MINSIZEREL + CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS_MINSIZEREL) + string(REGEX REPLACE "(^| )[/-]D *NDEBUG($| )" " " + ${rccFlagsVariable} "${${rccFlagsVariable}}") + endforeach() + endif() + endif() + add_compile_definitions(_GLIBCXX_ASSERTIONS) + check_cxx_source_compiles([=[ + #define _LIBCPP_HARDENING_MODE _LIBCPP_HARDENING_MODE_EXTENSIVE + #include <string> + int main() { return 0; } + ]=] RCC_SUPPORTS_LIBCXX_HARDENING_MODE) + if(RCC_SUPPORTS_LIBCXX_HARDENING_MODE) + add_compile_definitions(_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE) + endif() + endif() + + rcc_configure_standard_library_abi() + rcc_configure_platform_link_options() + rcc_configure_linker() + rcc_configure_platform_options() + rcc_configure_warning_options() + + if(RCC_USE_SANITIZER) + rcc_configure_sanitizer_options() + endif() + rcc_configure_debug_options() + rcc_configure_sections() + if(MSVC) + string(REGEX REPLACE "(^| ) */EH[-cs]+ *( |$)" "\\1 \\2" + CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + string(REGEX REPLACE "(^| ) */GR-? *( |$)" "\\1 \\2" + CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + endif() + rcc_configure_profile_options() + rcc_configure_pch_and_cache() + rcc_configure_lto() + rcc_configure_relative_paths() + rcc_configure_platform_definitions() +endmacro() + +macro(rcc_configure_sanitizer_options) + set(ubsanFlags "${RCC_UBSAN_FLAGS}") + set(sanitizerFlags) + set(commonFlags ON) + if(RCC_ON_UNIX) + if(RCC_USE_SANITIZER STREQUAL "Address") + list(APPEND sanitizerFlags -fsanitize=address) + elseif(RCC_USE_SANITIZER STREQUAL "HWAddress") + list(APPEND sanitizerFlags -fsanitize=hwaddress) + elseif(RCC_USE_SANITIZER MATCHES "Memory(WithOrigins)?") + list(APPEND sanitizerFlags -fsanitize=memory) + if(RCC_USE_SANITIZER STREQUAL "MemoryWithOrigins") + list(APPEND sanitizerFlags -fsanitize-memory-track-origins) + endif() + elseif(RCC_USE_SANITIZER STREQUAL "Undefined") + list(APPEND sanitizerFlags ${ubsanFlags}) + elseif(RCC_USE_SANITIZER STREQUAL "Thread") + list(APPEND sanitizerFlags -fsanitize=thread) + elseif(RCC_USE_SANITIZER STREQUAL "DataFlow") + list(APPEND sanitizerFlags -fsanitize=dataflow) + set(commonFlags OFF) + elseif(RCC_USE_SANITIZER STREQUAL "Address;Undefined" OR RCC_USE_SANITIZER STREQUAL "Undefined;Address") + list(APPEND sanitizerFlags -fsanitize=address ${ubsanFlags}) + elseif(RCC_USE_SANITIZER STREQUAL "Leaks") + list(APPEND sanitizerFlags -fsanitize=leak) + else() + message(FATAL_ERROR "Unsupported RCC_USE_SANITIZER value: ${RCC_USE_SANITIZER}") + endif() + elseif(MINGW OR MSVC) + if(NOT RCC_USE_SANITIZER MATCHES "^(Address|Undefined|Address;Undefined|Undefined;Address)$") + message(FATAL_ERROR "Unsupported sanitizer in this Windows environment: ${RCC_USE_SANITIZER}") + endif() + if("Address" IN_LIST RCC_USE_SANITIZER) + if(MSVC AND NOT RCC_CLANG_CL) + list(APPEND sanitizerFlags /fsanitize=address) + else() + list(APPEND sanitizerFlags -fsanitize=address) + endif() + endif() + if("Undefined" IN_LIST RCC_USE_SANITIZER) + if(MSVC AND NOT RCC_CLANG_CL) + message(FATAL_ERROR "Undefined sanitizer requires clang-cl in the MSVC environment") + endif() + list(APPEND sanitizerFlags ${ubsanFlags}) + endif() + else() + message(FATAL_ERROR "RCC_USE_SANITIZER is not supported on this platform") + endif() + + if(commonFlags) + if(MSVC AND NOT RCC_CLANG_CL) + rcc_append_flags("/Z7" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + rcc_append_flags("/debug" CMAKE_EXE_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) + foreach(rccFlagsVariable CMAKE_EXE_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) + string(REGEX REPLACE "(^| )/INCREMENTAL($| )" " /INCREMENTAL:NO " + ${rccFlagsVariable} "${${rccFlagsVariable}}") + endforeach() + if(CMAKE_C_COMPILER_ARCHITECTURE_ID STREQUAL "X86") + rcc_append_flags("/Oy-" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + else() + rcc_append_flags("-fno-omit-frame-pointer" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + if(NOT buildType STREQUAL "DEBUG" AND NOT buildType STREQUAL "RELWITHDEBINFO" + AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") + rcc_append_flags("-gline-tables-only" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + if(buildType STREQUAL "DEBUG" AND RCC_OPTIMIZE_SANITIZED_BUILDS) + rcc_append_flags("-O1" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + endif() + endif() + string(JOIN " " rccSanitizerFlags ${sanitizerFlags}) + rcc_append_flags("${rccSanitizerFlags}" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + + if(MSVC) + if(NOT RCC_CLANG_CL AND "Address" IN_LIST RCC_USE_SANITIZER) + foreach(rccFlagsVariable CMAKE_CXX_FLAGS_${buildType} CMAKE_C_FLAGS_${buildType}) + string(REGEX REPLACE "(^| )/RTC[1csu]*($| )" " " + ${rccFlagsVariable} "${${rccFlagsVariable}}") + endforeach() + endif() + if(RCC_LINKER_IS_LLD_LINK AND "Address" IN_LIST RCC_USE_SANITIZER) + if(CMAKE_C_COMPILER_ARCHITECTURE_ID STREQUAL "X86") + set(runtimeArch i386) + else() + set(runtimeArch x86_64) + endif() + rcc_append_flags("/opt:nolldtailmerge clang_rt.asan_dynamic-${runtimeArch}.lib" + CMAKE_EXE_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) + if(CMAKE_MSVC_RUNTIME_LIBRARY MATCHES "^(MultiThreaded|MultiThreadedDebug)$") + set(rccRuntimeThunk "clang_rt.asan_static_runtime_thunk-${runtimeArch}.lib") + else() + set(rccRuntimeThunk "clang_rt.asan_dynamic_runtime_thunk-${runtimeArch}.lib") + endif() + rcc_append_flags("/wholearchive:${rccRuntimeThunk}" + CMAKE_EXE_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) + endif() + endif() + + if(RCC_USE_SANITIZE_COVERAGE) + rcc_append_flags("-fsanitize=fuzzer-no-link" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + if(RCC_USE_SANITIZER MATCHES ".*Undefined.*") + set(rccIgnorelist "${PROJECT_SOURCE_DIR}/utils/sanitizers/ubsan_ignorelist.txt") + if(EXISTS "${rccIgnorelist}") + rcc_append_flags("-fsanitize-ignorelist=\"${rccIgnorelist}\"" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + endif() +endmacro() + +macro(rcc_configure_compiler_rt_path) + if(RCC_CLANG_CL AND (RCC_BUILD_INSTRUMENTED OR RCC_USE_SANITIZER)) + execute_process( + COMMAND "${CMAKE_CXX_COMPILER}" /clang:-print-libgcc-file-name /clang:--rtlib=compiler-rt + OUTPUT_VARIABLE rccCompilerRTFile + ERROR_VARIABLE rccClangCLError + RESULT_VARIABLE rccClangCLResult + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_STRIP_TRAILING_WHITESPACE) + if(NOT rccClangCLResult STREQUAL "0") + message(FATAL_ERROR "Unable to invoke clang-cl to find resource dir: ${rccClangCLError}") + endif() + file(TO_CMAKE_PATH "${rccCompilerRTFile}" rccCompilerRTFile) + get_filename_component(rccRuntimeDir "${rccCompilerRTFile}" DIRECTORY) + foreach(rccFlagsVariable CMAKE_EXE_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) + set(${rccFlagsVariable} + "${CMAKE_CXX_LINKER_WRAPPER_FLAG}/libpath:\"${rccRuntimeDir}\" ${${rccFlagsVariable}}") + endforeach() + endif() +endmacro() + +function(rcc_apply_options target) + set(enableEH ${RCC_ENABLE_EH}) + set(enableRTTI ${RCC_ENABLE_RTTI}) + if(RCC_REQUIRES_EH) + set(enableEH ON) + endif() + if(RCC_REQUIRES_RTTI) + set(enableRTTI ON) + endif() + if(enableEH AND NOT enableRTTI) + message(AUTHOR_WARNING "Exception handling requires RTTI; enabling RTTI for ${target}") + set(enableRTTI ON) + endif() + set(cxxFlags) + if(MSVC) + if(enableEH) + list(APPEND cxxFlags /EHsc) + else() + list(APPEND cxxFlags /EHs-c-) + target_compile_definitions(${target} PRIVATE _HAS_EXCEPTIONS=0) + endif() + if(enableRTTI) + list(APPEND cxxFlags /GR) + else() + list(APPEND cxxFlags /GR-) + endif() + elseif(RCC_GCC_COMPATIBLE) + if(NOT enableEH) + list(APPEND cxxFlags -fno-exceptions) + if(RCC_ENABLE_UNWIND_TABLES) + list(APPEND cxxFlags -funwind-tables) + else() + list(APPEND cxxFlags -fno-unwind-tables -fno-asynchronous-unwind-tables) + endif() + endif() + if(NOT enableRTTI) + list(APPEND cxxFlags -fno-rtti) + endif() + elseif(CMAKE_CXX_COMPILER_ID MATCHES "XL") + if(NOT enableEH) + list(APPEND cxxFlags -qnoeh) + endif() + if(NOT enableRTTI) + list(APPEND cxxFlags -qnortti) + endif() + endif() + target_compile_options(${target} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:${cxxFlags}>") + rcc_apply_link_options(${target}) +endfunction() + +macro(rcc_configure_additional_options) + option(BUILD_SHARED_LIBS "Build libraries as shared libraries instead of static" OFF) + if(NOT CMAKE_SYSTEM_NAME MATCHES "OS390") + option(RCC_ENABLE_PIC "Build position-independent code" ON) + endif() + option(RCC_ENABLE_LIBCXX "Use libc++ if available" OFF) + option(RCC_STATIC_LINK_CXX_STDLIB "Statically link the C++ standard library" OFF) + option(RCC_ENABLE_LLD "Use lld as the linker" OFF) + set(RCC_USE_LINKER "" CACHE STRING "Linker to select through the compiler driver") + set(RCC_ENABLE_LTO OFF CACHE STRING "Enable LTO; use Thin or Full to select its mode") + string(TOUPPER "${RCC_ENABLE_LTO}" rccLTOMode) + option(RCC_ENABLE_FATLTO "Build with fat LTO objects" OFF) + set(RCC_THINLTO_CACHE_PATH "${PROJECT_BINARY_DIR}/lto.cache" CACHE STRING "ThinLTO cache directory") + option(RCC_NO_DEAD_STRIP "Disable removal of unused sections" OFF) + option(RCC_USE_SPLIT_DWARF "Use split DWARF in debug builds" OFF) + option(RCC_USE_SANITIZE_COVERAGE "Enable sanitizer coverage without the fuzzer main function" OFF) + set(RCC_BUILD_INSTRUMENTED OFF CACHE STRING "PGO instrumentation: IR, Frontend, CSIR, CSSPGO") + option(RCC_BUILD_INSTRUMENTED_COVERAGE "Build with code coverage instrumentation" OFF) + mark_as_advanced(RCC_BUILD_INSTRUMENTED RCC_BUILD_INSTRUMENTED_COVERAGE) + set(RCC_PROFDATA_FILE "" CACHE FILEPATH "Instrumentation profile to use when compiling") + set(RCC_SPROFDATA_FILE "" CACHE FILEPATH "Sampling profile to use when compiling") + set(RCC_CCACHE_BUILD OFF CACHE BOOL "Enable ccache for compilation") + set(RCC_SOURCE_PREFIX "" CACHE STRING "Source prefix in mapped paths") + option(RCC_USE_RELATIVE_PATHS_IN_DEBUG_INFO "Use relative paths in debug information" OFF) + option(RCC_USE_RELATIVE_PATHS_IN_FILES "Use relative paths in source and debug information" OFF) + if(CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT (WIN32 OR CMAKE_SYSTEM_NAME MATCHES "AIX")) + option(RCC_BUILD_32_BITS "Build 32-bit binaries on a 64-bit platform" OFF) + endif() +endmacro() + +macro(rcc_configure_standard_library) + set(RCC_LIBCXX_USED OFF) + if(RCC_ENABLE_LIBCXX) + if(RCC_GCC_COMPATIBLE) + check_cxx_compiler_flag("-stdlib=libc++" RCC_COMPILER_SUPPORTS_LIBCXX) + check_linker_flag(CXX "-stdlib=libc++" RCC_LINKER_SUPPORTS_LIBCXX) + if(RCC_COMPILER_SUPPORTS_LIBCXX AND RCC_LINKER_SUPPORTS_LIBCXX) + rcc_append_flags("-stdlib=libc++" CMAKE_CXX_FLAGS + CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS) + set(RCC_LIBCXX_USED ON) + else() + message(WARNING "Cannot select libc++ with -stdlib=") + endif() + else() + message(WARNING "No libc++ selection flag is known for this compiler") + endif() + endif() + if(RCC_STATIC_LINK_CXX_STDLIB) + if(RCC_GCC_COMPATIBLE) + check_cxx_compiler_flag("-static-libstdc++" RCC_COMPILER_SUPPORTS_STATIC_STDLIB) + check_linker_flag(CXX "-static-libstdc++" RCC_LINKER_SUPPORTS_STATIC_STDLIB) + if(RCC_COMPILER_SUPPORTS_STATIC_STDLIB AND RCC_LINKER_SUPPORTS_STATIC_STDLIB) + rcc_append_flags("-static-libstdc++" + CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS) + else() + message(WARNING "Cannot select static linking for the C++ standard library") + endif() + else() + message(WARNING "No static C++ standard library selection flag is known for this compiler") + endif() + endif() +endmacro() + +macro(rcc_configure_standard_library_abi) + check_cxx_source_compiles([=[ + #include <iosfwd> + #if !defined(__GLIBCXX__) + #error Not libstdc++ + #endif + int main() { return 0; } + ]=] RCC_USES_LIBSTDCXX) + check_cxx_source_compiles([=[ + #include <string> + #if _GLIBCXX_USE_CXX11_ABI == 0 + #error C++11 ABI not active + #endif + int main() { return 0; } + ]=] RCC_DEFAULT_GLIBCXX_CXX11_ABI) + option(GLIBCXX_USE_CXX11_ABI "Use the libstdc++ C++11 ABI" ${RCC_DEFAULT_GLIBCXX_CXX11_ABI}) + if(RCC_USES_LIBSTDCXX) + if(GLIBCXX_USE_CXX11_ABI) + add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=1) + else() + add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0) + endif() + endif() +endmacro() + +macro(rcc_configure_linker) + if(RCC_ENABLE_LLD) + if(RCC_USE_LINKER) + message(FATAL_ERROR "RCC_ENABLE_LLD and RCC_USE_LINKER cannot be set together") + endif() + if(MSVC) + if(NOT CMAKE_LINKER MATCHES "lld-link") + get_filename_component(rccCXXCompilerDir "${CMAKE_CXX_COMPILER}" DIRECTORY) + get_filename_component(rccCCompilerDir "${CMAKE_C_COMPILER}" DIRECTORY) + find_program(RCC_LLD_LINK NAMES lld-link lld-link.exe + HINTS "${rccCXXCompilerDir}" "${rccCCompilerDir}") + if(NOT RCC_LLD_LINK) + message(FATAL_ERROR "RCC_ENABLE_LLD requires lld-link; set CMAKE_LINKER to its path") + endif() + set(CMAKE_LINKER "${RCC_LLD_LINK}") + endif() + else() + set(RCC_USE_LINKER lld) + endif() + endif() + if(RCC_USE_LINKER) + check_cxx_source_compiles("int main() { return 0; }" RCC_CAN_LINK_EXECUTABLE) + rcc_append_flags("-fuse-ld=${RCC_USE_LINKER}" + CMAKE_EXE_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) + if(RCC_CAN_LINK_EXECUTABLE) + check_cxx_source_compiles("int main() { return 0; }" RCC_SUPPORTS_CUSTOM_LINKER) + if(NOT RCC_SUPPORTS_CUSTOM_LINKER) + message(FATAL_ERROR "The compiler cannot link with -fuse-ld=${RCC_USE_LINKER}") + endif() + else() + message(STATUS "Skipping custom linker check: the target cannot link an executable") + endif() + endif() + set(RCC_LINKER_IS_LLD OFF) + set(RCC_LINKER_IS_LLD_LINK OFF) + if(CMAKE_LINKER MATCHES ".*lld" OR RCC_USE_LINKER STREQUAL "lld" OR RCC_ENABLE_LLD) + set(RCC_LINKER_IS_LLD ON) + endif() + if(CMAKE_LINKER MATCHES "lld-link" OR (MSVC AND (RCC_USE_LINKER STREQUAL "lld" OR RCC_ENABLE_LLD))) + set(RCC_LINKER_IS_LLD_LINK ON) + endif() + if(NOT WIN32) + if(APPLE) + set(rccLinkerVersionFlag "-Wl,-v") + else() + set(rccLinkerVersionFlag "-Wl,--version") + endif() + if(CMAKE_HOST_WIN32) + set(rccLinkerDevNull "NUL") + else() + set(rccLinkerDevNull "/dev/null") + endif() + if(RCC_USE_LINKER) + set(rccLinkerCommand ${CMAKE_C_COMPILER} -fuse-ld=${RCC_USE_LINKER} ${rccLinkerVersionFlag} -o ${rccLinkerDevNull}) + else() + separate_arguments(rccLinkerFlags UNIX_COMMAND "${CMAKE_EXE_LINKER_FLAGS}") + set(rccLinkerCommand ${CMAKE_C_COMPILER} ${rccLinkerFlags} ${rccLinkerVersionFlag} -o ${rccLinkerDevNull}) + endif() + execute_process(COMMAND ${rccLinkerCommand} + OUTPUT_VARIABLE rccLinkerOutput ERROR_VARIABLE rccLinkerError) + set(RCC_LINKER_IS_SOLARISLD OFF) + set(RCC_LINKER_IS_GNULD OFF) + if(rccLinkerOutput MATCHES "GNU ld") + set(RCC_LINKER_IS_GNULD ON) + endif() + if(rccLinkerOutput MATCHES "Solaris Link Editors" OR rccLinkerError MATCHES "Solaris Link Editors") + set(RCC_LINKER_IS_SOLARISLD ON) + endif() + endif() + if(APPLE) + if(NOT RCC_USE_LINKER) + check_linker_flag(C "-Wl,-no_warn_duplicate_libraries" RCC_LINKER_SUPPORTS_NO_WARN_DUPLICATE_LIBRARIES) + else() + set(RCC_LINKER_SUPPORTS_NO_WARN_DUPLICATE_LIBRARIES OFF CACHE INTERNAL "") + endif() + endif() +endmacro() + +function(rcc_has_no_incremental flags output) + set(${output} OFF PARENT_SCOPE) + string(FIND "${flags}" "/INCREMENTAL" position REVERSE) + if(position GREATER -1) + string(SUBSTRING "${flags}" ${position} 15 option) + if(option MATCHES "/INCREMENTAL:NO") + set(${output} ON PARENT_SCOPE) + endif() + endif() +endfunction() + +macro(rcc_configure_msvc_options) + add_compile_definitions(_CRT_SECURE_NO_DEPRECATE _CRT_SECURE_NO_WARNINGS + _CRT_NONSTDC_NO_DEPRECATE _CRT_NONSTDC_NO_WARNINGS + _SCL_SECURE_NO_DEPRECATE _SCL_SECURE_NO_WARNINGS UNICODE _UNICODE) + rcc_append_flags("/Zc:inline /Oi /permissive-" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + rcc_append_flags("/Zc:preprocessor" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + rcc_append_flags("/Zc:__cplusplus /bigobj" CMAKE_CXX_FLAGS) + set(RCC_WINSYSROOT "" CACHE STRING "Argument to clang-cl's /winsysroot") + if(RCC_WINSYSROOT) + if(NOT RCC_CLANG_CL) + message(FATAL_ERROR "RCC_WINSYSROOT requires clang-cl") + endif() + rcc_append_flags("/winsysroot\"${RCC_WINSYSROOT}\"" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + if(RCC_LINKER_IS_LLD_LINK) + rcc_append_flags("/winsysroot:\"${RCC_WINSYSROOT}\"" + CMAKE_EXE_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) + endif() + endif() + option(RCC_ENABLE_PDB "Generate PDB files in Release builds" OFF) + if(RCC_ENABLE_PDB AND buildType STREQUAL "RELEASE") + rcc_append_flags("/Zi" CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELEASE) + rcc_append_flags("/DEBUG /OPT:REF /OPT:ICF" + CMAKE_EXE_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) + endif() + set(rccAllLinkerFlags "") + foreach(rccKind EXE MODULE SHARED) + string(APPEND rccAllLinkerFlags + " ${CMAKE_${rccKind}_LINKER_FLAGS_${buildType}} ${CMAKE_${rccKind}_LINKER_FLAGS}") + endforeach() + string(TOUPPER "${rccAllLinkerFlags}" rccAllLinkerFlags) + if(RCC_CLANG_CL AND RCC_LINKER_IS_LLD AND rccAllLinkerFlags MATCHES "/DEBUG") + rcc_add_supported_warning("-gcodeview-ghash" GCODEVIEW_GHASH) + endif() + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT RCC_ENABLE_LTO) + foreach(rccKind EXE MODULE SHARED) + rcc_has_no_incremental( + "${CMAKE_${rccKind}_LINKER_FLAGS_${buildType}} ${CMAKE_${rccKind}_LINKER_FLAGS}" + rccNoIncremental${rccKind}) + endforeach() + if(rccNoIncrementalEXE AND rccNoIncrementalMODULE AND rccNoIncrementalSHARED) + add_compile_options("$<$<COMPILE_LANGUAGE:C,CXX>:/Brepro>") + add_link_options("LINKER:/Brepro") + else() + message(WARNING "/Brepro is incompatible with incremental linking; output will not be deterministic") + endif() + endif() +endmacro() + +macro(rcc_configure_platform_options) + if(RCC_ENABLE_PIC) + if(XCODE) + message(WARNING "-fPIC is not supported with Xcode") + elseif(NOT (WIN32 OR CYGWIN)) + check_c_compiler_flag("-Werror -fPIC" RCC_C_SUPPORTS_FPIC) + check_cxx_compiler_flag("-Werror -fPIC" RCC_CXX_SUPPORTS_FPIC) + if(RCC_C_SUPPORTS_FPIC AND RCC_CXX_SUPPORTS_FPIC) + message(STATUS "Building with -fPIC") + rcc_append_flags("-fPIC" CMAKE_C_FLAGS CMAKE_CXX_FLAGS CMAKE_ASM_FLAGS) + else() + message(WARNING "-fPIC is not supported") + endif() + if(NOT CMAKE_SYSTEM_NAME MATCHES "AIX" AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + rcc_add_supported_warning("-fno-semantic-interposition" FNO_SEMANTIC_INTERPOSITION) + endif() + endif() + endif() + if(NOT CMAKE_SYSTEM_NAME MATCHES "AIX" AND + (NOT (WIN32 OR CYGWIN) OR ((MINGW OR CYGWIN) AND CMAKE_CXX_COMPILER_ID MATCHES "Clang"))) + check_cxx_compiler_flag("-fvisibility-inlines-hidden" RCC_SUPPORTS_HIDDEN_INLINES) + if(RCC_SUPPORTS_HIDDEN_INLINES) + rcc_append_flags("-fvisibility-inlines-hidden" CMAKE_CXX_FLAGS) + endif() + endif() + + if((CMAKE_SIZEOF_VOID_P EQUAL 8 AND MINGW) OR CMAKE_SIZEOF_VOID_P EQUAL 4) + add_compile_definitions(_FILE_OFFSET_BITS=64) + endif() + if(CMAKE_SIZEOF_VOID_P EQUAL 4) + add_compile_definitions(_LARGEFILE_SOURCE) + endif() + if(CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT WIN32 AND RCC_BUILD_32_BITS) + message(STATUS "Building 32 bits executables and libraries.") + rcc_append_flags("-m32" CMAKE_C_FLAGS CMAKE_CXX_FLAGS + CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS) + add_compile_definitions(_LARGEFILE_SOURCE _FILE_OFFSET_BITS=64) + endif() + + if(MSVC OR CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC") + add_link_options("$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>:LINKER:/STACK:10000000>") + elseif(MINGW OR CYGWIN) + add_link_options("$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>:LINKER:--stack,16777216>") + if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang") + rcc_append_flags("-Wa,-mbig-obj" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + endif() + if(MSVC) + rcc_configure_msvc_options() + endif() + if(XCODE) + foreach(rccWarning + GCC_WARN_ABOUT_RETURN_TYPE GCC_WARN_ABOUT_MISSING_NEWLINE GCC_WARN_UNUSED_VALUE + GCC_WARN_UNUSED_VARIABLE GCC_WARN_SIGN_COMPARE GCC_WARN_UNUSED_FUNCTION + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS + GCC_WARN_UNINITIALIZED_AUTOS CLANG_WARN_BOOL_CONVERSION CLANG_WARN_EMPTY_BODY + CLANG_WARN_ENUM_CONVERSION CLANG_WARN_INT_CONVERSION CLANG_WARN_CONSTANT_CONVERSION + GCC_WARN_NON_VIRTUAL_DESTRUCTOR) + set(CMAKE_XCODE_ATTRIBUTE_${rccWarning} YES) + endforeach() + endif() + if(MSVC_IDE) + set(RCC_COMPILER_JOBS "0" CACHE STRING "Parallel compiler jobs; 0 uses all processors") + if(RCC_COMPILER_JOBS STREQUAL "0") + add_compile_options(/MP) + elseif(NOT RCC_COMPILER_JOBS STREQUAL "1") + message(STATUS "Number of parallel compiler jobs set to ${RCC_COMPILER_JOBS}") + add_compile_options("/MP${RCC_COMPILER_JOBS}") + else() + message(STATUS "Parallel compilation disabled") + endif() + endif() + +endmacro() + +macro(rcc_configure_sections) + if(NOT CYGWIN AND NOT MSVC) + if(NOT CMAKE_SYSTEM_NAME MATCHES "Darwin" AND NOT buildType STREQUAL "DEBUG") + if(CMAKE_CXX_COMPILER_ID MATCHES "XL") + rcc_append_flags("-qfuncsect" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + else() + rcc_append_flags("-ffunction-sections" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + rcc_append_flags("-fdata-sections" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + elseif(MSVC AND NOT buildType STREQUAL "DEBUG") + rcc_append_flags("/Gw" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() +endmacro() + +macro(rcc_configure_debug_options) + if(RCC_USE_SPLIT_DWARF AND (buildType STREQUAL "DEBUG" OR buildType STREQUAL "RELWITHDEBINFO") + AND CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") + add_compile_options("$<$<COMPILE_LANGUAGE:C,CXX>:-gsplit-dwarf>") + check_linker_flag(CXX "-Wl,--gdb-index" RCC_LINKER_SUPPORTS_GDB_INDEX) + if(RCC_LINKER_SUPPORTS_GDB_INDEX) + rcc_append_flags("-Wl,--gdb-index" CMAKE_EXE_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) + endif() + endif() + if(RCC_ENABLE_PIC AND RCC_USING_GLIBC) + check_cxx_source_compiles([=[ + #include <cstdio> + #if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 36) + #error RELR requires glibc 2.36 + #endif + int main() { return 0; } + ]=] RCC_GLIBC_SUPPORTS_RELR) + if(RCC_GLIBC_SUPPORTS_RELR) + check_linker_flag(CXX "-Wl,-z,pack-relative-relocs" RCC_LINKER_SUPPORTS_RELR) + if(RCC_LINKER_SUPPORTS_RELR) + rcc_append_flags("-Wl,-z,pack-relative-relocs" + CMAKE_EXE_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) + endif() + endif() + endif() + add_compile_definitions(__STDC_CONSTANT_MACROS __STDC_FORMAT_MACROS __STDC_LIMIT_MACROS) + if(UNIX AND CMAKE_GENERATOR MATCHES "Ninja") + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") + rcc_append_flags("-fdiagnostics-color" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + check_linker_flag(CXX "-Wl,--color-diagnostics" RCC_LINKER_SUPPORTS_COLOR_DIAGNOSTICS) + if(RCC_LINKER_SUPPORTS_COLOR_DIAGNOSTICS) + rcc_append_flags("-Wl,--color-diagnostics" + CMAKE_EXE_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) + endif() + endif() +endmacro() + +macro(rcc_configure_profile_options) + string(TOUPPER "${RCC_BUILD_INSTRUMENTED}" rccProfileMode) + if(RCC_BUILD_INSTRUMENTED OR RCC_BUILD_INSTRUMENTED_COVERAGE) + if(NOT RCC_PROFILE_MERGE_POOL_SIZE) + set(RCC_PROFILE_MERGE_POOL_SIZE 4) + endif() + if(NOT RCC_PROFILE_FILE_PATTERN) + if(NOT RCC_PROFILE_DATA_DIR) + file(TO_NATIVE_PATH "${PROJECT_BINARY_DIR}/profiles" RCC_PROFILE_DATA_DIR) + endif() + file(TO_NATIVE_PATH "${RCC_PROFILE_DATA_DIR}/%${RCC_PROFILE_MERGE_POOL_SIZE}m.profraw" RCC_PROFILE_FILE_PATTERN) + endif() + if(NOT RCC_CSPROFILE_FILE_PATTERN) + if(NOT RCC_CSPROFILE_DATA_DIR) + file(TO_NATIVE_PATH "${PROJECT_BINARY_DIR}/csprofiles" RCC_CSPROFILE_DATA_DIR) + endif() + file(TO_NATIVE_PATH "${RCC_CSPROFILE_DATA_DIR}/%${RCC_PROFILE_MERGE_POOL_SIZE}m.profraw" RCC_CSPROFILE_FILE_PATTERN) + endif() + endif() + if(RCC_BUILD_INSTRUMENTED AND RCC_BUILD_INSTRUMENTED_COVERAGE) + message(FATAL_ERROR "PGO instrumentation and coverage instrumentation cannot both be enabled") + endif() + if(RCC_BUILD_INSTRUMENTED) + if(rccProfileMode STREQUAL "IR") + set(rccProfileFlags "-fprofile-generate=\"${RCC_PROFILE_DATA_DIR}\"") + elseif(rccProfileMode STREQUAL "CSIR") + set(rccProfileFlags "-fcs-profile-generate=\"${RCC_CSPROFILE_DATA_DIR}\"") + elseif(rccProfileMode STREQUAL "CSSPGO") + if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang") + message(FATAL_ERROR "RCC_BUILD_INSTRUMENTED=CSSPGO requires Clang") + endif() + set(rccProfileFlags + "-fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -fno-optimize-sibling-calls -fpseudo-probe-for-profiling -fdebug-info-for-profiling") + else() + set(rccProfileFlags "-fprofile-instr-generate=\"${RCC_PROFILE_FILE_PATTERN}\"") + endif() + rcc_append_flags("${rccProfileFlags}" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + if(NOT RCC_LINKER_IS_LLD_LINK) + rcc_append_flags("${rccProfileFlags}" CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) + endif() + endif() + rcc_configure_compiler_rt_path() + + if(RCC_PROFDATA_FILE AND EXISTS "${RCC_PROFDATA_FILE}") + if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang") + message(FATAL_ERROR "RCC_PROFDATA_FILE requires Clang") + endif() + rcc_append_flags("-fprofile-instr-use=\"${RCC_PROFDATA_FILE}\"" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + if(NOT RCC_LINKER_IS_LLD_LINK) + rcc_append_flags("-fprofile-instr-use=\"${RCC_PROFDATA_FILE}\"" + CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) + endif() + elseif(RCC_PROFDATA_FILE) + message(WARNING "RCC_PROFDATA_FILE does not exist: ${RCC_PROFDATA_FILE}") + endif() + if(RCC_SPROFDATA_FILE AND EXISTS "${RCC_SPROFDATA_FILE}") + if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang") + message(FATAL_ERROR "RCC_SPROFDATA_FILE requires Clang") + endif() + set(rccSampleFlags "-fpseudo-probe-for-profiling -fprofile-sample-use=\"${RCC_SPROFDATA_FILE}\"") + rcc_append_flags("${rccSampleFlags}" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + if(NOT RCC_LINKER_IS_LLD_LINK) + rcc_append_flags("${rccSampleFlags}" CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) + endif() + endif() + if(RCC_BUILD_INSTRUMENTED_COVERAGE) + rcc_append_flags("-fprofile-instr-generate=\"${RCC_PROFILE_FILE_PATTERN}\" -fcoverage-mapping" + CMAKE_C_FLAGS CMAKE_CXX_FLAGS CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) + endif() +endmacro() + +macro(rcc_configure_lto) + if(RCC_ENABLE_LTO AND WIN32 AND NOT RCC_LINKER_IS_LLD_LINK AND NOT MINGW) + message(FATAL_ERROR "LTO on Windows requires lld-link; set CMAKE_LINKER to its path") + endif() + if(RCC_ENABLE_LTO) + if(rccLTOMode STREQUAL "THIN") + set(rccLTOFlag "-flto=thin") + elseif(rccLTOMode STREQUAL "FULL") + set(rccLTOFlag "-flto=full") + else() + set(rccLTOFlag "-flto") + endif() + rcc_append_flags("${rccLTOFlag}" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + if(NOT RCC_LINKER_IS_LLD_LINK) + rcc_append_flags("${rccLTOFlag}" CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) + endif() + endif() + if(rccLTOMode STREQUAL "THIN") + if(APPLE) + rcc_append_flags("-Wl,-cache_path_lto,${RCC_THINLTO_CACHE_PATH}" + CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) + elseif(CMAKE_SYSTEM_NAME MATCHES "AIX") + rcc_append_flags("-bplugin_opt:-legacy-thinlto-cache-dir=${RCC_THINLTO_CACHE_PATH}" + CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) + elseif((UNIX OR MINGW) AND RCC_USE_LINKER STREQUAL "lld") + rcc_append_flags("-Wl,--thinlto-cache-dir=${RCC_THINLTO_CACHE_PATH}" + CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) + elseif(RCC_USE_LINKER STREQUAL "gold") + rcc_append_flags("-Wl,--plugin-opt,cache-dir=${RCC_THINLTO_CACHE_PATH}" + CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) + elseif(RCC_LINKER_IS_LLD_LINK) + rcc_append_flags("/lldltocache:${RCC_THINLTO_CACHE_PATH}" + CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) + endif() + endif() + if(RCC_ENABLE_FATLTO AND ((UNIX AND NOT APPLE) OR FUCHSIA)) + rcc_append_flags("-ffat-lto-objects" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + if(NOT RCC_LINKER_IS_LLD_LINK) + rcc_append_flags("-ffat-lto-objects" + CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS) + endif() + endif() +endmacro() + +macro(rcc_configure_pch_and_cache) + if(NOT DEFINED CMAKE_DISABLE_PRECOMPILE_HEADERS) + if(CMAKE_SYSTEM_NAME MATCHES "OS390") + message(NOTICE "Precompiled headers are disabled by default on z/OS. " + "Pass -DCMAKE_DISABLE_PRECOMPILE_HEADERS=OFF to override.") + set(CMAKE_DISABLE_PRECOMPILE_HEADERS ON) + endif() + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + message(NOTICE "Precompiled headers are disabled by default with GCC. " + "Pass -DCMAKE_DISABLE_PRECOMPILE_HEADERS=OFF to override.") + set(CMAKE_DISABLE_PRECOMPILE_HEADERS ON) + endif() + if(CMAKE_CXX_COMPILER_LAUNCHER MATCHES "sccache") + message(NOTICE "Precompiled headers are disabled by default with sccache. " + "Pass -DCMAKE_DISABLE_PRECOMPILE_HEADERS=OFF to override.") + set(CMAKE_DISABLE_PRECOMPILE_HEADERS ON) + elseif(CMAKE_CXX_COMPILER_LAUNCHER MATCHES "clang-cache") + message(NOTICE "Precompiled headers are disabled by default with clang-cache. " + "Pass -DCMAKE_DISABLE_PRECOMPILE_HEADERS=OFF to override.") + set(CMAKE_DISABLE_PRECOMPILE_HEADERS ON) + elseif(RCC_CCACHE_BUILD OR CMAKE_CXX_COMPILER_LAUNCHER MATCHES "ccache") + if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang") + message(WARNING "Using ccache with precompiled headers with non-Clang " + "compilers is not supported and may lead to false positives. " + "Set CMAKE_DISABLE_PRECOMPILE_HEADERS to ON/OFF to silence this warning.") + set(CMAKE_DISABLE_PRECOMPILE_HEADERS ON) + endif() + if(CMAKE_HOST_WIN32) + message(WARNING "Using ccache with precompiled headers on Windows is " + "currently not supported. " + "Pass -DCMAKE_DISABLE_PRECOMPILE_HEADERS=OFF to override.") + set(CMAKE_DISABLE_PRECOMPILE_HEADERS ON) + endif() + endif() + endif() + if(NOT CMAKE_DISABLE_PRECOMPILE_HEADERS) + message(STATUS "Precompiled headers enabled.") + set(CMAKE_PCH_PROLOGUE "") + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + rcc_append_flags("-Xclang -fno-pch-timestamp" CMAKE_CXX_FLAGS) + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + rcc_append_flags("-fpch-preprocess" CMAKE_CXX_FLAGS) + endif() + else() + message(STATUS "Precompiled headers disabled.") + endif() + if(RCC_CCACHE_BUILD) + find_program(RCC_CCACHE_PROGRAM ccache) + if(NOT RCC_CCACHE_PROGRAM) + message(FATAL_ERROR "ccache was not found; install it or disable RCC_CCACHE_BUILD") + endif() + set(RCC_CCACHE_MAXSIZE "" CACHE STRING "ccache size limit") + set(RCC_CCACHE_DIR "" CACHE STRING "ccache storage directory") + set(RCC_CCACHE_PARAMS "CCACHE_CPP2=yes CCACHE_HASHDIR=yes CCACHE_SLOPPINESS=pch_defines,time_macros" + CACHE STRING "Environment assignments for ccache") + if(NOT CMAKE_HOST_WIN32) + set(rccCacheCommand "${RCC_CCACHE_PARAMS} \"${RCC_CCACHE_PROGRAM}\"") + if(NOT CMAKE_DISABLE_PRECOMPILE_HEADERS) + set(rccCacheCommand "CCACHE_DEPEND=1 ${rccCacheCommand}") + endif() + if(RCC_CCACHE_MAXSIZE) + set(rccCacheCommand "CCACHE_MAXSIZE=${RCC_CCACHE_MAXSIZE} ${rccCacheCommand}") + endif() + if(RCC_CCACHE_DIR) + set(rccCacheCommand "CCACHE_DIR=\"${RCC_CCACHE_DIR}\" ${rccCacheCommand}") + endif() + set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${rccCacheCommand}") + message(STATUS "ccache program: ${rccCacheCommand}") + else() + if(RCC_CCACHE_MAXSIZE OR RCC_CCACHE_DIR OR + NOT RCC_CCACHE_PARAMS MATCHES "CCACHE_CPP2=yes CCACHE_HASHDIR=yes CCACHE_SLOPPINESS=pch_defines,time_macros") + message(FATAL_ERROR "Configure ccache through environment variables on Windows") + endif() + set(CMAKE_C_COMPILER_LAUNCHER "${RCC_CCACHE_PROGRAM}") + set(CMAKE_CXX_COMPILER_LAUNCHER "${RCC_CCACHE_PROGRAM}") + message(STATUS "ccache program: ${RCC_CCACHE_PROGRAM}") + endif() + endif() +endmacro() + +macro(rcc_configure_relative_paths) + if(RCC_USE_RELATIVE_PATHS_IN_DEBUG_INFO OR RCC_USE_RELATIVE_PATHS_IN_FILES) + if(RCC_ENABLE_PROJECTS) + get_filename_component(rccSourceRoot "${PROJECT_SOURCE_DIR}/.." ABSOLUTE) + else() + set(rccSourceRoot "${PROJECT_SOURCE_DIR}") + endif() + file(RELATIVE_PATH rccRelativeRoot "${CMAKE_BINARY_DIR}" "${rccSourceRoot}") + endif() + if(RCC_USE_RELATIVE_PATHS_IN_DEBUG_INFO) + check_c_compiler_flag("-fdebug-prefix-map=foo=bar" RCC_SUPPORTS_FDEBUG_PREFIX_MAP) + if(RCC_SUPPORTS_FDEBUG_PREFIX_MAP) + rcc_append_flags("-fdebug-prefix-map=\"${CMAKE_BINARY_DIR}=${rccRelativeRoot}\" -fdebug-prefix-map=\"${rccSourceRoot}/=${RCC_SOURCE_PREFIX}\"" + CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + if(RCC_GCC_COMPATIBLE) + rcc_append_flags("-no-canonical-prefixes" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + endif() + if(RCC_USE_RELATIVE_PATHS_IN_FILES) + check_c_compiler_flag("-ffile-prefix-map=foo=bar" RCC_SUPPORTS_FFILE_PREFIX_MAP) + if(RCC_SUPPORTS_FFILE_PREFIX_MAP) + rcc_append_flags("-ffile-prefix-map=\"${CMAKE_BINARY_DIR}=${rccRelativeRoot}\" -ffile-prefix-map=\"${rccSourceRoot}/=${RCC_SOURCE_PREFIX}\"" + CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + if(RCC_GCC_COMPATIBLE) + rcc_append_flags("-no-canonical-prefixes" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + endif() + endif() +endmacro() + +function(rcc_apply_link_options target) + if(NOT buildType STREQUAL "DEBUG") + if(NOT RCC_NO_DEAD_STRIP) + if(CMAKE_SYSTEM_NAME MATCHES "Darwin") + target_link_options(${target} PRIVATE "LINKER:-dead_strip") + elseif(CMAKE_SYSTEM_NAME STREQUAL "SunOS" AND RCC_LINKER_IS_SOLARISLD) + check_linker_flag(CXX "-Wl,-z,discard-unused=sections" RCC_LINKER_SUPPORTS_DISCARD_UNUSED) + if(RCC_LINKER_SUPPORTS_DISCARD_UNUSED) + target_link_options(${target} PRIVATE "LINKER:-z,discard-unused=sections") + endif() + elseif(NOT MSVC AND NOT CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC" AND NOT CMAKE_SYSTEM_NAME MATCHES "AIX|OS390") + target_link_options(${target} PRIVATE "LINKER:--gc-sections") + endif() + elseif(CMAKE_SYSTEM_NAME MATCHES "AIX") + target_link_options(${target} PRIVATE "LINKER:-bnogc") + endif() + endif() + if(RCC_LINKER_SUPPORTS_NO_WARN_DUPLICATE_LIBRARIES) + target_link_options(${target} PRIVATE "LINKER:-no_warn_duplicate_libraries") + endif() +endfunction() diff --git a/rcc/cmake/modules/HandleRCCStdlib.cmake b/rcc/cmake/modules/HandleRCCStdlib.cmake new file mode 100644 index 0000000..5dcaf2e --- /dev/null +++ b/rcc/cmake/modules/HandleRCCStdlib.cmake @@ -0,0 +1,54 @@ +# This CMake module is responsible for setting the standard library to libc++ +# if the user has requested it. + +include(DetermineGCCCompatible) + +if(NOT DEFINED RCC_STDLIB_HANDLED) + set(RCC_STDLIB_HANDLED ON) + + function(append value) + foreach(variable ${ARGN}) + set(${variable} "${${variable}} ${value}" PARENT_SCOPE) + endforeach(variable) + endfunction() + + include(CheckCXXCompilerFlag) + include(CheckLinkerFlag) + set(RCC_LIBCXX_USED 0) + if(RCC_ENABLE_LIBCXX) + if(RCC_COMPILER_IS_GCC_COMPATIBLE) + check_cxx_compiler_flag("-stdlib=libc++" CXX_COMPILER_SUPPORTS_STDLIB) + check_linker_flag(CXX "-stdlib=libc++" CXX_LINKER_SUPPORTS_STDLIB) + if(CXX_COMPILER_SUPPORTS_STDLIB AND CXX_LINKER_SUPPORTS_STDLIB) + append("-stdlib=libc++" + CMAKE_CXX_FLAGS CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS + CMAKE_MODULE_LINKER_FLAGS) + set(RCC_LIBCXX_USED 1) + else() + message(WARNING "Can't specify libc++ with '-stdlib='") + endif() + else() + message(WARNING "Not sure how to specify libc++ for this compiler") + endif() + endif() + + if(RCC_STATIC_LINK_CXX_STDLIB) + if(RCC_COMPILER_IS_GCC_COMPATIBLE) + check_cxx_compiler_flag("-static-libstdc++" + CXX_COMPILER_SUPPORTS_STATIC_STDLIB) + check_linker_flag(CXX "-static-libstdc++" CXX_LINKER_SUPPORTS_STATIC_STDLIB) + if(CXX_COMPILER_SUPPORTS_STATIC_STDLIB AND + CXX_LINKER_SUPPORTS_STATIC_STDLIB) + append("-static-libstdc++" + CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS + CMAKE_MODULE_LINKER_FLAGS) + else() + message(WARNING + "Can't specify static linking for the C++ standard library") + endif() + else() + message(WARNING "Not sure how to specify static linking of C++ standard " + "library for this compiler") + endif() + endif() +endif() diff --git a/rcc/cmake/modules/RCCConfig.cmake.in b/rcc/cmake/modules/RCCConfig.cmake.in new file mode 100644 index 0000000..3454a58 --- /dev/null +++ b/rcc/cmake/modules/RCCConfig.cmake.in @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: GPL-3.0-or-later + +@PACKAGE_INIT@ + +set(RCC_VERSION "@RCC_VERSION@") +set(RCC_VERSION_MAJOR "@RCC_VERSION_MAJOR@") +set(RCC_VERSION_MINOR "@RCC_VERSION_MINOR@") +set(RCC_VERSION_PATCH "@RCC_VERSION_PATCH@") +set(RCC_CMAKE_DIR "@RCC_PACKAGE_MODULE_DIR@") +set(RCC_INCLUDE_DIRS "@RCC_PACKAGE_INCLUDE_DIRS@") +set(RCC_LIBRARY_DIR "@RCC_PACKAGE_LIBRARY_DIR@") +set(RCC_BUILD_LIBRARY_DIR "@RCC_PACKAGE_BUILD_LIBRARY_DIR@") +set(RCC_INSTALL_PREFIX "@RCC_PACKAGE_INSTALL_PREFIX@") +set(RCC_ENABLE_ASSERTIONS "@RCC_ENABLE_ASSERTIONS@") +set(RCC_ENABLE_EH "@RCC_ENABLE_EH@") +set(RCC_ENABLE_RTTI "@RCC_ENABLE_RTTI@") +set(RCC_ENABLE_UNWIND_TABLES "@RCC_ENABLE_UNWIND_TABLES@") +set(RCC_ENABLE_WARNINGS "@RCC_ENABLE_WARNINGS@") +set(RCC_ENABLE_WARNING_SUPPRESSIONS "@RCC_ENABLE_WARNING_SUPPRESSIONS@") +set(RCC_ENABLE_LIBCXX "@RCC_LIBCXX_USED@") +set(RCC_STATIC_LINK_CXX_STDLIB "@RCC_STATIC_LINK_CXX_STDLIB@") +set(GLIBCXX_USE_CXX11_ABI "@GLIBCXX_USE_CXX11_ABI@") +set(RCC_DEFINITIONS "@RCC_DEFINITIONS@") +if(MSVC) + set(CMAKE_MSVC_RUNTIME_LIBRARY "@RCC_PACKAGE_MSVC_RUNTIME_LIBRARY@") +endif() +include("${CMAKE_CURRENT_LIST_DIR}/RCCTargets.cmake") diff --git a/rcc/cmake/modules/RCCConfigVersion.cmake.in b/rcc/cmake/modules/RCCConfigVersion.cmake.in new file mode 100644 index 0000000..f7d5ea4 --- /dev/null +++ b/rcc/cmake/modules/RCCConfigVersion.cmake.in @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-3.0-or-later + +set(PACKAGE_VERSION "@PROJECT_VERSION@") + +# Match major and minor versions; accept the requested patch version or newer. +if("@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@" VERSION_EQUAL + "${PACKAGE_FIND_VERSION_MAJOR}.${PACKAGE_FIND_VERSION_MINOR}" + AND NOT "@PROJECT_VERSION_PATCH@" VERSION_LESS "${PACKAGE_FIND_VERSION_PATCH}") + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if("@PROJECT_VERSION_PATCH@" VERSION_EQUAL "${PACKAGE_FIND_VERSION_PATCH}") + set(PACKAGE_VERSION_EXACT TRUE) + endif() +endif() |
