# ********************************************************** # Copyright (c) 2012-2025 Google, Inc. All rights reserved. # ********************************************************** # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # * Neither the name of Google, Inc. nor the names of its contributors may be # used to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE, INC. OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. # CMAKE_CURRENT_LIST_DIR wasn't added until 2.8.3 get_filename_component(utils_cmake_dir "${CMAKE_CURRENT_LIST_FILE}" PATH) include(${utils_cmake_dir}/utils_exposed.cmake) # sets CMAKE_COMPILER_IS_CLANG and CMAKE_COMPILER_IS_GNUCC in parent scope function (identify_clang) _DR_identify_clang() if (CMAKE_COMPILER_IS_GNUCC) set(CMAKE_COMPILER_IS_GNUCC TRUE PARENT_SCOPE) endif () set(CMAKE_COMPILER_IS_CLANG ${CMAKE_COMPILER_IS_CLANG} PARENT_SCOPE) endfunction (identify_clang) function (append_property_string type target name value) _DR_append_property_string(${type} ${target} ${name} "${value}") endfunction (append_property_string) function (append_property_list type target name value) # XXX: if we require cmake 2.8.6 we can simply use APPEND_LIST get_property(cur ${type} ${target} PROPERTY ${name}) if (cur) set(value ${cur} ${value}) endif (cur) set_property(${type} ${target} PROPERTY ${name} ${value}) endfunction (append_property_list) function(get_full_path out target loc_suffix) DynamoRIO_get_full_path(local ${target} "${loc_suffix}") set(${out} ${local} PARENT_SCOPE) endfunction (get_full_path) function (get_target_path_for_execution out target loc_suffix) if (ANDROID) DynamoRIO_get_target_path_for_execution(local ${target} ${DR_DEVICE_BASEDIR} "${loc_suffix}") else () DynamoRIO_get_target_path_for_execution(local ${target} "" "${loc_suffix}") endif () set(${out} ${local} PARENT_SCOPE) endfunction (get_target_path_for_execution) function (prefix_cmd_if_necessary cmd_out use_ats cmd_in) DynamoRIO_prefix_cmd_if_necessary(local ${use_ats} ${cmd_in} ${ARGN}) set(${cmd_out} ${local} PARENT_SCOPE) endfunction (prefix_cmd_if_necessary) # i#1873: we copy individual targets for speed, using up less space, and to # support "make test" as well as a much nicer rebuild-and-rerun dev model, # rather than a massive "adb push" at the very end of the build. function (copy_target_to_device target loc_suffix) if (DR_COPY_TO_DEVICE) DynamoRIO_copy_target_to_device(${target} ${DR_DEVICE_BASEDIR} "${loc_suffix}") endif () endfunction (copy_target_to_device) function (add_rel_rpaths target) DynamoRIO_add_rel_rpaths(${target} ${ARGN}) endfunction (add_rel_rpaths) function (check_if_linker_is_gnu_gold var_out) _DR_check_if_linker_is_gnu_gold(is_gold) set(${var_out} ${is_gold} PARENT_SCOPE) endfunction (check_if_linker_is_gnu_gold) function (check_if_linker_is_llvm_lld var_out) _DR_check_if_linker_is_llvm_lld(is_lld) set(${var_out} ${is_lld} PARENT_SCOPE) endfunction (check_if_linker_is_llvm_lld) # disable known warnings function (disable_compiler_warnings) if (WIN32) # disable stack protection: "unresolved external symbol ___security_cookie" # disable the warning "unreferenced formal parameter" #4100 # disable the warning "conditional expression is constant" #4127 # disable the warning "cast from function pointer to data pointer" #4054 set(CL_CFLAGS "/GS- /wd4100 /wd4127 /wd4054") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CL_CFLAGS}" PARENT_SCOPE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CL_CFLAGS}" PARENT_SCOPE) add_definitions(-D_CRT_SECURE_NO_WARNINGS) endif (WIN32) endfunction (disable_compiler_warnings) # clients/extensions don't include configure.h so they don't get DR defines macro (add_dr_defines) foreach (config "" ${CMAKE_BUILD_TYPE} ${CMAKE_CONFIGURATION_TYPES}) if ("${config}" STREQUAL "") set(config_upper "") else ("${config}" STREQUAL "") string(TOUPPER "_${config}" config_upper) endif ("${config}" STREQUAL "") foreach (var CMAKE_C_FLAGS${config_upper};CMAKE_CXX_FLAGS${config_upper}) if (DEBUG) set(${var} "${${var}} -DDEBUG") endif (DEBUG) # we're used to X64 instead of X86_64 if (X64) set(${var} "${${var}} -DX64") endif (X64) endforeach (var) endforeach (config) endmacro (add_dr_defines) macro (install_subdirs tgt_lib tgt_bin) # These cover all subdirs. # Subdirs just need to install their targets. DR_install(DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/ DESTINATION ${tgt_lib} FILE_PERMISSIONS ${owner_access} OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE FILES_MATCHING PATTERN "*.debug" PATTERN "*.pdb" REGEX ".*.dSYM/.*DWARF/.*" # too painful to get right # of backslash for literal . ${ARGN} ) # We rely on our shared library targets being redirected to # CMAKE_LIBRARY_OUTPUT_DIRECTORY in order to copy the shared lib pdbs # and executable pdbs into the right places. Callers can use # place_shared_lib_in_lib_dir() to accomplish this. DR_install(DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ DESTINATION ${tgt_bin} FILE_PERMISSIONS ${owner_access} OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE FILES_MATCHING PATTERN "*.debug" PATTERN "*.pdb" REGEX ".*.dSYM/.*DWARF/.*" # too painful to get right # of backslash for literal . ${ARGN} ) endmacro (install_subdirs) # Use this to put shared libraries in the lib dir to separate them from # executables in the output dir. function (place_shared_lib_in_lib_dir target) set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY${location_suffix} "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}" RUNTIME_OUTPUT_DIRECTORY${location_suffix} "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}" ARCHIVE_OUTPUT_DIRECTORY${location_suffix} "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") endfunction () function (check_avx_processor_and_compiler_support out) if (WIN32) # XXX i#1312: add Windows support. message(FATAL_ERROR "Windows not supported yet.") endif () include(CheckCSourceRuns) set(avx_prog "#include int main() { register __m256 ymm0 asm(\"ymm0\"); (void)ymm0; asm volatile(\"vmovdqu %ymm0, %ymm1\"); return 0; }") set(CMAKE_REQUIRED_FLAGS ${CFLAGS_AVX}) check_c_source_runs("${avx_prog}" proc_found_avx) if (proc_found_avx) message(STATUS "Compiler and processor support AVX.") else () message(STATUS "WARNING: Compiler or processor do not support AVX. " "Skipping tests") endif () set(${out} ${proc_found_avx} PARENT_SCOPE) endfunction (check_avx_processor_and_compiler_support) function (check_avx2_processor_and_compiler_support out) if (WIN32) # XXX i#1312: add Windows support. message(FATAL_ERROR "Windows not supported yet.") endif () include(CheckCSourceRuns) set(avx2_prog "#include int main() { register __m256 ymm0 asm(\"ymm0\"); (void)ymm0; asm volatile(\"vpsravd %ymm0, %ymm1, %ymm0\"); return 0; }") set(CMAKE_REQUIRED_FLAGS ${CFLAGS_AVX2}) check_c_source_runs("${avx2_prog}" proc_found_avx2) if (proc_found_avx2) message(STATUS "Compiler and processor support AVX2.") else () message(STATUS "WARNING: Compiler or processor do not support AVX2. " "Skipping tests") endif () set(${out} ${proc_found_avx2} PARENT_SCOPE) endfunction (check_avx2_processor_and_compiler_support) function (check_avx512_processor_and_compiler_support out) if (WIN32) # XXX i#1312: add Windows support. message(FATAL_ERROR "Windows not supported yet.") endif () include(CheckCSourceRuns) set(avx512_prog "#include int main() { register __m512 zmm0 asm(\"zmm0\"); (void)zmm0; asm volatile(\"vmovdqu64 %zmm0, %zmm1\"); return 0; }") set(CMAKE_REQUIRED_FLAGS ${CFLAGS_AVX512}) check_c_source_runs("${avx512_prog}" proc_found_avx512) if (proc_found_avx512) message(STATUS "Compiler and processor support AVX-512.") else () message(STATUS "WARNING: Compiler or processor do not support AVX-512. " "Skipping tests") endif () set(${out} ${proc_found_avx512} PARENT_SCOPE) endfunction (check_avx512_processor_and_compiler_support) # Check if the building machine support Intel PT. # This function only checks if PT-related tests need to be built. PT-capable # binaries can be built on any system. When building an export module, please # do not use it to check if PT-related libraries need to be built. function(check_intel_pt_support out) if (NOT LINUX OR NOT X86 OR NOT X64) message(STATUS "Intel PT not supported on this platform.") set(${out} 0 PARENT_SCOPE) else () if (EXISTS "/sys/devices/intel_pt/type") message(STATUS "Intel PT is available.") set(${out} 1 PARENT_SCOPE) else () message(STATUS "Intel PT not found.") set(${out} 0 PARENT_SCOPE) endif() endif () endfunction(check_intel_pt_support) if (UNIX) # We always use a script for our own library bounds (PR 361594). # We could build this at configure time instead of build time as # it does not depend on the source files. # XXX: this is duplicated in DynamoRIOConfig.cmake function (set_preferred_base_start_and_end target base set_bounds) if (APPLE) set(ldflags "-image_base ${base}") elseif (NOT LINKER_IS_GNU_GOLD AND NOT LINKER_IS_LLVM_LLD) set(ld_script ${CMAKE_CURRENT_BINARY_DIR}/${target}.ldscript) set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${ld_script}") set(ldflags "-Wl,${ld_script_option},\"${ld_script}\"") add_custom_command(TARGET ${target} PRE_LINK COMMAND ${CMAKE_COMMAND} # script does not inherit any vars so we must pass them all in # to work around i#84 be sure to put a space after -D for 1st arg at least ARGS -D outfile=${ld_script} -DCMAKE_LINKER=${CMAKE_LINKER} -DCMAKE_COMPILER_IS_GNUCC=${CMAKE_COMPILER_IS_GNUCC} -DLD_FLAGS=${LD_FLAGS} -Dset_preferred=${SET_PREFERRED_BASE} -Dreplace_maxpagesize=${REPLACE_MAXPAGESIZE} -Dpreferred_base=${base} -Dadd_bounds_vars=${set_bounds} -P ${PROJECT_SOURCE_DIR}/make/ldscript.cmake VERBATIM # recommended: p260 ) else () set(ldflags "") if (SET_PREFERRED_BASE) if (LINKER_IS_LLVM_LLD) set(ldflags "-Wl,--image-base=${base}") else () # XXX: This should be -Ttext-segment for bfd, but most golds want -Ttext. # See http://sourceware.org/ml/binutils/2013-02/msg00194.html set(ldflags "-Wl,-Ttext=${base}") endif () endif () if (set_bounds) # Add our start and end symbols for library bounds. # XXX: hardcoded to dynamorio for now: generalize when necessary. set(ldflags "${ldflags} -Wl,--defsym,dynamorio_so_start=__executable_start") set(ldflags "${ldflags} -Wl,--defsym,dynamorio_so_end=end") endif () endif () if (ARM AND NOT set_bounds) # XXX: don't want for libDR: using "set_bounds" for now # Somehow the entry point gets changed to A32 by using ldscript. # Adding --entry causes the linker to set it to either A32 or T32 as appropriate. set(ldflags "${ldflags} -Wl,--entry -Wl,_start") endif () append_property_string(TARGET ${target} LINK_FLAGS "${ldflags}") endfunction (set_preferred_base_start_and_end) endif (UNIX) function (check_sve_processor_and_compiler_support out vl_out) include(CheckCSourceRuns) set(sve_prog "#include #include int main() { uint64_t vl = 0; asm(\"rdvl %[dest], 1\" : [dest] \"=r\" (vl) : :); printf(\"%lu\", vl * 8); return 0; }") set(CMAKE_REQUIRED_FLAGS ${CFLAGS_SVE}) if (CMAKE_CROSSCOMPILING) # If we are cross-compiling check_c_source_runs() can't run the executable on the # host to find out whether the target processor supports SVE, so we assume it # doesn't. set(proc_found_sve_EXITCODE 1 CACHE STRING "Set to 0 if target processor/emulator supports SVE to enable SVE tests" FORCE) else () file(WRITE "${PROJECT_BINARY_DIR}/sve_check.c" "${sve_prog}\n") try_run(proc_found_sve_EXITCODE proc_found_sve_COMPILED ${PROJECT_BINARY_DIR} ${PROJECT_BINARY_DIR}/sve_check.c CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${CFLAGS_SVE} RUN_OUTPUT_VARIABLE sve_vl ) if (NOT proc_found_sve_COMPILED) set(proc_found_sve_EXITCODE 1) endif() endif () if (${proc_found_sve_EXITCODE} EQUAL 0) message(STATUS "Compiler and processor support SVE (VL=${sve_vl}).") set(${out} 1 PARENT_SCOPE) set(${vl_out} ${sve_vl} PARENT_SCOPE) else () message(STATUS "WARNING: Compiler or processor do not support SVE. " "Skipping tests") set(${out} 0 PARENT_SCOPE) endif () endfunction (check_sve_processor_and_compiler_support) function (check_feature_processor_and_compiler_support feat_name c_flags test_prog out) include(CheckCSourceRuns) set(CMAKE_REQUIRED_FLAGS ${c_flags}) if (CMAKE_CROSSCOMPILING) # If we are cross-compiling check_c_source_runs() can't run the executable on the # host to find out whether the target processor supports the feature, so we assume it # doesn't. set(proc_found_${feat_name}_EXITCODE 1 CACHE STRING "Set to 0 if target processor/emulator supports ${feat_name} to enable ${feat_name} tests" FORCE) else () check_c_source_runs("${test_prog}" proc_found_${feat_name}) endif () if (proc_found_${feat_name}) message(STATUS "Compiler and processor support ${feat_name}.") else () message(STATUS "WARNING: Compiler or processor do not support ${feat_name}. " "Skipping tests") endif () set(${out} ${proc_found_${feat_name}} PARENT_SCOPE) endfunction (check_feature_processor_and_compiler_support) macro (check_sve2_processor_and_compiler_support out) check_feature_processor_and_compiler_support(sve2 ${CFLAGS_SVE2} "int main() { asm(\"histcnt z0.d, p0/z, z0.d, z0.d\"); return 0; }" ${out} ) endmacro (check_sve2_processor_and_compiler_support) macro (check_pauth_processor_and_compiler_support out) check_feature_processor_and_compiler_support(pauth ${CFLAGS_PAUTH} "int main() { void *addr = 0; asm(\"paciza %[ptr]\" : [ptr] \"+r\" (addr) : :); return 0; }" ${out} ) endmacro (check_pauth_processor_and_compiler_support) function (get_processor_vendor out) set(cpu_vendor "") if (APPLE) find_program(SYSCTL NAMES sysctl PATHS /usr/sbin) if (SYSCTL) execute_process(COMMAND ${SYSCTL} -n machdep.cpu.vendor OUTPUT_VARIABLE cpu_vendor OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_VARIABLE err) if ("${cpu_vendor}" STREQUAL "") execute_process(COMMAND ${SYSCTL} -n machdep.cpu.brand_string OUTPUT_VARIABLE cpu_vendor OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_VARIABLE err) endif () endif () elseif (WIN32) get_filename_component(cpu_vendor "[HKEY_LOCAL_MACHINE\\Hardware\\Description\\System\\CentralProcessor\\0;VendorIdentifier]" NAME) elseif (EXISTS "/proc/cpuinfo") set (regex ".*vendor_id[ \t]*:[ \t]+([a-zA-Z0-9_-]+).*") file(READ "/proc/cpuinfo" contents) if (contents MATCHES ${regex}) string(REGEX REPLACE ${regex} "\\1" cpu_vendor "${contents}") endif () endif () message(STATUS "Processor vendor is ${cpu_vendor}") set(${out} ${cpu_vendor} PARENT_SCOPE) endfunction ()