blob: eeda4c004f4e13493cb5808a861df117b760b59b [file] [edit]
# Similarly to Autoconf's ax_check_vscript.m4, check whether the linker supports
# version scripts (GNU ld) or map files (Sun linker).
# Sets the "have_var" to TRUE or FALSE depending on the detected support; and if
# support is detected then sets "flag_var" to the appropriate flag to pass to
# the linker (namely, --version-script or -M).
# Helper function: try to compile a shared library with a given linker flag and
# version script. This properly tests version script support by building a
# shared library rather than an executable, avoiding issues with
# executable-specific symbols (e.g. FreeBSD's crt1.o symbols, Solaris linker
# symbols in values-Xc.o).
function(_pcre2_try_vscript_shared_lib link_flag map_file result_var)
if(DEFINED ${result_var})
return()
endif()
message(STATUS "Performing Test ${result_var}")
set(${result_var} FALSE PARENT_SCOPE)
set(try_dir "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CMakeScratch/CheckVscript")
file(REMOVE_RECURSE "${try_dir}")
file(MAKE_DIRECTORY "${try_dir}")
# Write a minimal C source with exported symbols
file(WRITE "${try_dir}/test_vscript.c" "
int hidethis(void) { return 0; }
int exposethis(void) { return hidethis(); }
")
# Write a CMakeLists.txt that builds a shared library with the version script
file(WRITE "${try_dir}/CMakeLists.txt" "
cmake_minimum_required(VERSION 3.15)
project(test_vscript C)
add_library(test_vscript SHARED test_vscript.c)
target_link_options(test_vscript PRIVATE \"-Wl,${link_flag},${map_file}\")
")
try_compile(
compile_result
"${try_dir}/build" # BINARY_DIR
"${try_dir}" # SOURCE_DIR
test_vscript # Project name
OUTPUT_VARIABLE compile_output
)
if(compile_result)
set(${result_var} TRUE PARENT_SCOPE)
endif()
if(${compile_result})
set(${result_var} 1 CACHE INTERNAL "Test ${result_var}")
message(STATUS "Performing Test ${result_var} - Success")
else()
set(${result_var} "" CACHE INTERNAL "Test ${result_var}")
message(STATUS "Performing Test ${result_var} - Failed")
endif()
endfunction()
function(pcre2_check_vscript have_var flag_var no_star_var)
set(${have_var} FALSE PARENT_SCOPE)
set(${flag_var} "" PARENT_SCOPE)
set(${no_star_var} FALSE PARENT_SCOPE)
if(MSVC)
return()
endif()
set(first_run FALSE)
if(NOT DEFINED HAVE_VSCRIPT_GNU)
set(first_run TRUE)
message(STATUS "Detecting linker version script support")
endif()
# Write test version script files
file(WRITE "${PROJECT_BINARY_DIR}/test-map-file.sym" "PCRE2_10.00 { global: exposethis; local: *; };")
file(WRITE "${PROJECT_BINARY_DIR}/test-map-file-broken.sym" "PCRE2_10.00 { global: exposethis; local: *; }; {")
file(WRITE "${PROJECT_BINARY_DIR}/test-map-file-no-star.sym" "PCRE2_10.00 { global: exposethis; local: hidethis; };")
set(HAVE_VSCRIPT FALSE)
# Test GNU ld --version-script flag
_pcre2_try_vscript_shared_lib("--version-script" "${PROJECT_BINARY_DIR}/test-map-file.sym" HAVE_VSCRIPT_GNU)
if(HAVE_VSCRIPT_GNU)
set(VSCRIPT_FLAG --version-script)
set(HAVE_VSCRIPT TRUE)
else()
# Test Sun linker -M flag
_pcre2_try_vscript_shared_lib("-M" "${PROJECT_BINARY_DIR}/test-map-file.sym" HAVE_VSCRIPT_SUN)
if(HAVE_VSCRIPT_SUN)
set(VSCRIPT_FLAG -M)
set(HAVE_VSCRIPT TRUE)
endif()
endif()
if(HAVE_VSCRIPT)
# Perform the same logic as ax_check_vscript.m4, to test whether the linker
# silently ignores (and overwrites) linker scripts it doesn't understand.
_pcre2_try_vscript_shared_lib("${VSCRIPT_FLAG}" "${PROJECT_BINARY_DIR}/test-map-file-broken.sym" HAVE_VSCRIPT_BROKEN)
if(HAVE_VSCRIPT_BROKEN)
set(HAVE_VSCRIPT FALSE)
endif()
endif()
if(first_run)
if(HAVE_VSCRIPT)
message(STATUS "Detecting linker version script support - yes (${VSCRIPT_FLAG})")
elseif(HAVE_VSCRIPT_BROKEN)
message(STATUS "Detecting linker version script support - no (linker overwrites unknown scripts)")
else()
message(STATUS "Detecting linker version script support - none detected")
endif()
endif()
if(HAVE_VSCRIPT)
if(first_run)
message(STATUS "Detecting if version scripts work without wildcard")
endif()
# Test that the linker works without requiring a wildcard to hide platform-specific
# symbols (_init, _fini, etc.).
_pcre2_try_vscript_shared_lib("${VSCRIPT_FLAG}" "${PROJECT_BINARY_DIR}/test-map-file-no-star.sym" HAVE_VSCRIPT_NO_STAR)
if(first_run)
message(STATUS "Detecting if version scripts work without wildcard - ${HAVE_VSCRIPT_NO_STAR}")
endif()
endif()
file(REMOVE "${PROJECT_BINARY_DIR}/test-map-file.sym")
file(REMOVE "${PROJECT_BINARY_DIR}/test-map-file-broken.sym")
file(REMOVE "${PROJECT_BINARY_DIR}/test-map-file-no-star.sym")
if(HAVE_VSCRIPT)
set(${have_var} TRUE PARENT_SCOPE)
set(${flag_var} "${VSCRIPT_FLAG}" PARENT_SCOPE)
set(${no_star_var} "${HAVE_VSCRIPT_NO_STAR}" PARENT_SCOPE)
endif()
endfunction()