Skip to content

Commit 990d53f

Browse files
authored
Add linker scripts with symbol versioning (#721)
Both the Autoconf and CMake build systems are updated to detect linker support for symbol versioning. Currently, Linux, Solaris, and FreeBSD are tested and working. Windows (COFF) and macOS (Mach-O) have no symbol versioning. There is an Autoconf/CMake flag to opt out of the versioning behaviour.
1 parent b3ecb62 commit 990d53f

21 files changed

+880
-278
lines changed

CMakeLists.txt

Lines changed: 90 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@
108108
# Applied to all CMake files using:
109109
# > pip3 install gersemi
110110
# > gersemi --in-place --line-length 120 --indent 2 \
111-
# ./CMakeLists.txt ./cmake/*.cmake ./cmake/*.cmake.in
111+
# --definitions cmake/*.cmake \
112+
# -- ./CMakeLists.txt ./cmake/*.cmake ./cmake/*.cmake.in
112113
################################################################################
113114

114115
# Increased minimum to 3.15 to allow use of string(REPEAT).
@@ -123,10 +124,12 @@ set(CMAKE_C_VISIBILITY_PRESET hidden)
123124
# recently added to CMake for the `cc` compiler (Oracle Developer Studio). The
124125
# CMake version from OpenCSW and Oracle's package repository is too old and
125126
# requires this fix.
126-
if (CMAKE_SYSTEM_NAME STREQUAL "SunOS" AND
127-
CMAKE_VERSION VERSION_LESS 3.31 AND
128-
CMAKE_C_COMPILER_ID STREQUAL "SunPro" AND
129-
CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 5.15)
127+
if(
128+
CMAKE_SYSTEM_NAME STREQUAL "SunOS"
129+
AND CMAKE_VERSION VERSION_LESS 3.31
130+
AND CMAKE_C_COMPILER_ID STREQUAL "SunPro"
131+
AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 5.15
132+
)
130133
set(CMAKE_C_COMPILE_OPTIONS_VISIBILITY "-fvisibility=")
131134
endif()
132135

@@ -158,6 +161,7 @@ include(CheckSymbolExists)
158161
include(CheckIncludeFile)
159162
include(CheckTypeSize)
160163
include(GNUInstallDirs) # for CMAKE_INSTALL_LIBDIR
164+
include(PCRE2CheckLinkerFlag)
161165

162166
check_include_file(assert.h HAVE_ASSERT_H)
163167
check_include_file(dirent.h HAVE_DIRENT_H)
@@ -200,6 +204,12 @@ check_c_source_compiles(
200204
HAVE_VISIBILITY
201205
)
202206

207+
if(HAVE_VISIBILITY)
208+
set(PCRE2_EXPORT [=[__attribute__ ((visibility ("default")))]=])
209+
else()
210+
set(PCRE2_EXPORT)
211+
endif()
212+
203213
set(CMAKE_REQUIRED_FLAGS ${ORIG_CMAKE_REQUIRED_FLAGS})
204214

205215
check_c_source_compiles("int main(void) { __assume(1); return 0; }" HAVE_BUILTIN_ASSUME)
@@ -217,11 +227,33 @@ check_c_source_compiles(
217227
HAVE_BUILTIN_UNREACHABLE
218228
)
219229

220-
if(HAVE_VISIBILITY)
221-
set(PCRE2_EXPORT [=[__attribute__ ((visibility ("default")))]=])
222-
else()
223-
set(PCRE2_EXPORT)
230+
# Detect support for linker scripts.
231+
232+
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/test-map-file.sym "PCRE2_10.00 { global: main; };")
233+
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/test-map-file-broken.sym "PCRE2_10.00 { global: main; }; {")
234+
pcre2_check_linker_flag(C -Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/test-map-file.sym HAVE_VSCRIPT_GNU)
235+
pcre2_check_linker_flag(C -Wl,-M,${CMAKE_CURRENT_BINARY_DIR}/test-map-file.sym HAVE_VSCRIPT_SUN)
236+
if(HAVE_VSCRIPT_GNU)
237+
set(VSCRIPT_FLAG --version-script)
238+
set(HAVE_VSCRIPT TRUE)
239+
elseif(HAVE_VSCRIPT_SUN)
240+
set(VSCRIPT_FLAG -M)
241+
set(HAVE_VSCRIPT TRUE)
242+
endif()
243+
if(HAVE_VSCRIPT)
244+
# Perform the same logic as ax_check_vscript.m4, to test whether the linker
245+
# silently ignores (and overwrites) linker scripts it doesn't understand.
246+
pcre2_check_linker_flag(
247+
C
248+
-Wl,${VSCRIPT_FLAG},${CMAKE_CURRENT_BINARY_DIR}/test-map-file-broken.sym
249+
HAVE_VSCRIPT_BROKEN
250+
)
251+
if(HAVE_VSCRIPT_BROKEN)
252+
set(HAVE_VSCRIPT FALSE)
253+
endif()
224254
endif()
255+
file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/test-map-file.sym)
256+
file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/test-map-file-broken.sym)
225257

226258
# Check whether Intel CET is enabled, and if so, adjust compiler flags. This
227259
# code was written by PH, trying to imitate the logic from the autotools
@@ -272,7 +304,12 @@ set(
272304

273305
set(PCRE2_EBCDIC_NL25 OFF CACHE BOOL "Use 0x25 as EBCDIC NL character instead of 0x15; implies EBCDIC.")
274306

275-
set(PCRE2_EBCDIC_IGNORING_COMPILER OFF CACHE BOOL "Force EBCDIC 1047 using numeric literals rather than C character literals; implies EBCDIC.")
307+
set(
308+
PCRE2_EBCDIC_IGNORING_COMPILER
309+
OFF
310+
CACHE BOOL
311+
"Force EBCDIC 1047 using numeric literals rather than C character literals; implies EBCDIC."
312+
)
276313

277314
option(PCRE2_REBUILD_CHARTABLES "Rebuild char tables" OFF)
278315

@@ -388,6 +425,10 @@ if(MSVC)
388425
option(INSTALL_MSVC_PDB "ON=Install .pdb files built by MSVC, if generated" OFF)
389426
endif()
390427

428+
if(HAVE_VSCRIPT)
429+
option(PCRE2_SYMVERS "Enable library symbol versioning" ON)
430+
endif()
431+
391432
# bzip2 lib
392433
if(BZIP2_FOUND)
393434
option(PCRE2_SUPPORT_LIBBZ2 "Enable support for linking pcre2grep with libbz2." ON)
@@ -705,9 +746,17 @@ if(REBUILD_CHARTABLES)
705746
elseif(NOT PCRE2_EBCDIC)
706747
configure_file(${PROJECT_SOURCE_DIR}/src/pcre2_chartables.c.dist ${PROJECT_BINARY_DIR}/pcre2_chartables.c COPYONLY)
707748
elseif(PCRE2_EBCDIC_NL25)
708-
configure_file(${PROJECT_SOURCE_DIR}/src/pcre2_chartables.c.ebcdic-1047-nl25 ${PROJECT_BINARY_DIR}/pcre2_chartables.c COPYONLY)
749+
configure_file(
750+
${PROJECT_SOURCE_DIR}/src/pcre2_chartables.c.ebcdic-1047-nl25
751+
${PROJECT_BINARY_DIR}/pcre2_chartables.c
752+
COPYONLY
753+
)
709754
else()
710-
configure_file(${PROJECT_SOURCE_DIR}/src/pcre2_chartables.c.ebcdic-1047-nl15 ${PROJECT_BINARY_DIR}/pcre2_chartables.c COPYONLY)
755+
configure_file(
756+
${PROJECT_SOURCE_DIR}/src/pcre2_chartables.c.ebcdic-1047-nl15
757+
${PROJECT_BINARY_DIR}/pcre2_chartables.c
758+
COPYONLY
759+
)
711760
endif()
712761

713762
# Source code
@@ -882,6 +931,10 @@ if(PCRE2_BUILD_PCRE2_8)
882931
if(REQUIRE_PTHREAD)
883932
target_link_libraries(pcre2-8-shared Threads::Threads)
884933
endif()
934+
if(HAVE_VSCRIPT AND PCRE2_SYMVERS)
935+
target_link_options(pcre2-8-shared PRIVATE -Wl,${VSCRIPT_FLAG},${PROJECT_SOURCE_DIR}/src/libpcre2-8.sym)
936+
set_target_properties(pcre2-8-shared PROPERTIES LINK_DEPENDS ${PROJECT_SOURCE_DIR}/src/libpcre2-8.sym)
937+
endif()
885938
set(TARGETS ${TARGETS} pcre2-8-shared)
886939
set(DLL_PDB_FILES $<TARGET_PDB_FILE_DIR:pcre2-8-shared>/pcre2-8.pdb ${DLL_PDB_FILES})
887940
set(DLL_PDB_DEBUG_FILES $<TARGET_PDB_FILE_DIR:pcre2-8-shared>/pcre2-8d.pdb ${DLL_PDB_DEBUG_FILES})
@@ -898,6 +951,10 @@ if(PCRE2_BUILD_PCRE2_8)
898951
SOVERSION ${LIBPCRE2_POSIX_SOVERSION}
899952
OUTPUT_NAME pcre2-posix
900953
)
954+
if(HAVE_VSCRIPT AND PCRE2_SYMVERS)
955+
target_link_options(pcre2-posix-shared PRIVATE -Wl,${VSCRIPT_FLAG},${PROJECT_SOURCE_DIR}/src/libpcre2-posix.sym)
956+
set_target_properties(pcre2-posix-shared PROPERTIES LINK_DEPENDS ${PROJECT_SOURCE_DIR}/src/libpcre2-posix.sym)
957+
endif()
901958
set(PCRE2POSIX_CFLAG "-DPCRE2POSIX_SHARED")
902959
target_compile_definitions(pcre2-posix-shared PUBLIC ${PCRE2POSIX_CFLAG})
903960
target_link_libraries(pcre2-posix-shared pcre2-8-shared)
@@ -971,6 +1028,10 @@ if(PCRE2_BUILD_PCRE2_16)
9711028
if(REQUIRE_PTHREAD)
9721029
target_link_libraries(pcre2-16-shared Threads::Threads)
9731030
endif()
1031+
if(HAVE_VSCRIPT AND PCRE2_SYMVERS)
1032+
target_link_options(pcre2-16-shared PRIVATE -Wl,${VSCRIPT_FLAG},${PROJECT_SOURCE_DIR}/src/libpcre2-16.sym)
1033+
set_target_properties(pcre2-16-shared PROPERTIES LINK_DEPENDS ${PROJECT_SOURCE_DIR}/src/libpcre2-16.sym)
1034+
endif()
9741035
set(TARGETS ${TARGETS} pcre2-16-shared)
9751036
set(DLL_PDB_FILES $<TARGET_PDB_FILE_DIR:pcre2-16-shared>/pcre2-16.pdb ${DLL_PDB_FILES})
9761037
set(DLL_PDB_DEBUG_FILES $<TARGET_PDB_FILE_DIR:pcre2-16-shared>/pcre2-16d.pdb ${DLL_PDB_DEBUG_FILES})
@@ -1039,6 +1100,10 @@ if(PCRE2_BUILD_PCRE2_32)
10391100
if(REQUIRE_PTHREAD)
10401101
target_link_libraries(pcre2-32-shared Threads::Threads)
10411102
endif()
1103+
if(HAVE_VSCRIPT AND PCRE2_SYMVERS)
1104+
target_link_options(pcre2-32-shared PRIVATE -Wl,${VSCRIPT_FLAG},${PROJECT_SOURCE_DIR}/src/libpcre2-32.sym)
1105+
set_target_properties(pcre2-32-shared PROPERTIES LINK_DEPENDS ${PROJECT_SOURCE_DIR}/src/libpcre2-32.sym)
1106+
endif()
10421107
set(TARGETS ${TARGETS} pcre2-32-shared)
10431108
set(DLL_PDB_FILES $<TARGET_PDB_FILE_DIR:pcre2-32-shared>/pcre2-32.pdb ${DLL_PDB_FILES})
10441109
set(DLL_PDB_DEBUG_FILES $<TARGET_PDB_FILE_DIR:pcre2-32-shared>/pcre2-32d.pdb ${DLL_PDB_DEBUG_FILES})
@@ -1372,9 +1437,9 @@ if(PCRE2_SHOW_REPORT)
13721437
else()
13731438
message(STATUS " Build type ........................ : ${CMAKE_BUILD_TYPE}")
13741439
endif()
1375-
message(STATUS " Build 8 bit PCRE2 library ......... : ${PCRE2_BUILD_PCRE2_8}")
1376-
message(STATUS " Build 16 bit PCRE2 library ........ : ${PCRE2_BUILD_PCRE2_16}")
1377-
message(STATUS " Build 32 bit PCRE2 library ........ : ${PCRE2_BUILD_PCRE2_32}")
1440+
message(STATUS " Build 8 bit pcre2 library ......... : ${PCRE2_BUILD_PCRE2_8}")
1441+
message(STATUS " Build 16 bit pcre2 library ........ : ${PCRE2_BUILD_PCRE2_16}")
1442+
message(STATUS " Build 32 bit pcre2 library ........ : ${PCRE2_BUILD_PCRE2_32}")
13781443
message(STATUS " Include debugging code ............ : ${PCRE2_DEBUG}")
13791444
message(STATUS " Enable JIT compiling support ...... : ${PCRE2_SUPPORT_JIT}")
13801445
message(STATUS " Use SELinux allocator in JIT ...... : ${PCRE2_SUPPORT_JIT_SEALLOC}")
@@ -1397,18 +1462,24 @@ if(PCRE2_SHOW_REPORT)
13971462

13981463
message(STATUS " Internal link size ................ : ${PCRE2_LINK_SIZE}")
13991464
message(STATUS " Maximum variable lookbehind ....... : ${PCRE2_MAX_VARLOOKBEHIND}")
1400-
message(STATUS " Parentheses nest limit ............ : ${PCRE2_PARENS_NEST_LIMIT}")
1465+
message(STATUS " Nested parentheses limit .......... : ${PCRE2_PARENS_NEST_LIMIT}")
14011466
message(STATUS " Heap limit ........................ : ${PCRE2_HEAP_LIMIT}")
14021467
message(STATUS " Match limit ....................... : ${PCRE2_MATCH_LIMIT}")
14031468
message(STATUS " Match depth limit ................. : ${PCRE2_MATCH_LIMIT_DEPTH}")
14041469
message(STATUS " Build shared libs ................. : ${BUILD_SHARED_LIBS}")
1470+
if(NOT HAVE_VSCRIPT)
1471+
message(STATUS " with symbol versioning ........ : n/a")
1472+
else()
1473+
message(STATUS " with symbol versioning ........ : ${PCRE2_SYMVERS}")
1474+
endif()
14051475
message(STATUS " Build static libs ................. : ${BUILD_STATIC_LIBS}")
1406-
message(STATUS " with PIC enabled ............... : ${PCRE2_STATIC_PIC}")
1476+
message(STATUS " with PIC enabled .............. : ${PCRE2_STATIC_PIC}")
14071477
message(STATUS " Build pcre2grep ................... : ${PCRE2_BUILD_PCRE2GREP}")
14081478
message(STATUS " Enable JIT in pcre2grep ........... : ${PCRE2GREP_SUPPORT_JIT}")
14091479
message(STATUS " Enable callouts in pcre2grep ...... : ${PCRE2GREP_SUPPORT_CALLOUT}")
14101480
message(STATUS " Enable callout fork in pcre2grep .. : ${PCRE2GREP_SUPPORT_CALLOUT_FORK}")
1411-
message(STATUS " Buffer size for pcre2grep ......... : ${PCRE2GREP_BUFSIZE}")
1481+
message(STATUS " Initial buffer size for pcre2grep . : ${PCRE2GREP_BUFSIZE}")
1482+
message(STATUS " Maximum buffer size for pcre2grep . : ${PCRE2GREP_MAX_BUFSIZE}")
14121483
message(STATUS " Build tests (implies pcre2test .... : ${PCRE2_BUILD_TESTS}")
14131484
message(STATUS " and pcre2grep)")
14141485
if(ZLIB_FOUND)
@@ -1431,7 +1502,7 @@ if(PCRE2_SHOW_REPORT)
14311502
else()
14321503
message(STATUS " Link pcre2test with libreadline ... : Library not found")
14331504
endif()
1434-
message(STATUS " Support Valgrind .................. : ${PCRE2_SUPPORT_VALGRIND}")
1505+
message(STATUS " Enable Valgrind support ........... : ${PCRE2_SUPPORT_VALGRIND}")
14351506
if(PCRE2_DISABLE_PERCENT_ZT)
14361507
message(STATUS " Use %zu and %td ................... : OFF")
14371508
else()

Makefile.am

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,10 @@ EXTRA_DIST =
276276
# These files contain additional m4 macros that are used by autoconf.
277277

278278
EXTRA_DIST += \
279-
m4/ax_pthread.m4 m4/pcre2_visibility.m4
279+
m4/ax_check_vscript.m4 \
280+
m4/ax_pthread.m4 \
281+
m4/pcre2_visibility.m4 \
282+
m4/pcre2_zos.m4
280283

281284
# These files contain maintenance information
282285

@@ -891,6 +894,13 @@ pkgconfig_DATA += libpcre2-32.pc
891894
endif
892895

893896

897+
# Symbol version files for use with GNU and Sun ld.
898+
899+
EXTRA_DIST += \
900+
src/libpcre2-8.sym src/libpcre2-16.sym src/libpcre2-32.sym \
901+
src/libpcre2-posix.sym
902+
903+
894904
# gcov/lcov code coverage reporting
895905
#
896906
# Coverage reporting targets:
@@ -1001,6 +1011,7 @@ EXTRA_DIST += \
10011011
cmake/FindReadline.cmake \
10021012
cmake/pcre2-config-version.cmake.in \
10031013
cmake/pcre2-config.cmake.in \
1014+
cmake/PCRE2CheckLinkerFlag.cmake \
10041015
src/config-cmake.h.in \
10051016
CMakeLists.txt
10061017

README

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,9 @@ library. They are also documented in the pcre2build man page.
169169
versions of all the relevant libraries are available for linking. See also
170170
"Shared libraries" below.
171171

172+
Shared libraries are compiled with symbol versioning enabled on platforms that
173+
support this, but this can be disabled by adding --disable-symvers.
174+
172175
. By default, only the 8-bit library is built. If you add --enable-pcre2-16 to
173176
the "configure" command, the 16-bit library is also built. If you add
174177
--enable-pcre2-32 to the "configure" command, the 32-bit library is also
@@ -956,6 +959,10 @@ The distribution should contain the files listed below.
956959
testdata/testoutput* expected test results
957960
testdata/grep* input and output for pcre2grep tests
958961
testdata/* other supporting test files
962+
src/libpcre2-8.sym )
963+
src/libpcre2-16.sym ) symbol version scripts for the GNU and Sun linkers
964+
src/libpcre2-32.sym )
965+
src/libpcre2-posix.sym )
959966

960967
(D) Auxiliary files for CMake support
961968

@@ -964,6 +971,7 @@ The distribution should contain the files listed below.
964971
cmake/FindReadline.cmake
965972
cmake/pcre2-config-version.cmake.in
966973
cmake/pcre2-config.cmake.in
974+
cmake/PCRE2CheckLinkerFlag.cmake
967975
src/config-cmake.h.in
968976
CMakeLists.txt
969977

cmake/PCRE2CheckLinkerFlag.cmake

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
include(CheckLinkerFlag OPTIONAL)
2+
3+
# This file can be removed once the minimum CMake version is increased to 3.18
4+
# or higher. Calls to pcre2_check_linker_flag can be changed to the built in
5+
# check_linker_flag.
6+
7+
if(COMMAND check_linker_flag)
8+
macro(pcre2_check_linker_flag)
9+
check_linker_flag(${ARGN})
10+
endmacro()
11+
else()
12+
# Fallback for versions of CMake older than 3.18.
13+
14+
include(CheckCCompilerFlag)
15+
16+
function(pcre2_check_linker_flag lang flag out_var)
17+
cmake_policy(PUSH)
18+
cmake_policy(SET CMP0056 NEW)
19+
set(_CMAKE_EXE_LINKER_FLAGS_SAVE ${CMAKE_EXE_LINKER_FLAGS})
20+
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${flag}")
21+
check_c_compiler_flag("" ${out_var})
22+
set(CMAKE_EXE_LINKER_FLAGS ${_CMAKE_EXE_LINKER_FLAGS_SAVE})
23+
cmake_policy(POP)
24+
endfunction()
25+
endif()

0 commit comments

Comments
 (0)