Skip to content

Commit 3c7951b

Browse files
Cleanup pkg-config (#1326)
* New generations of pkg-config files * Remove unused pc templates * Fix: Allow _BSD_SOURCE to affect ResSearch.cmake
1 parent aa6c681 commit 3c7951b

12 files changed

+319
-201
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ list (APPEND CMAKE_MODULE_PATH
88
)
99

1010
include (MongoSettings)
11+
include (GeneratePkgConfig)
1112

1213
# Subcomponents:
1314
mongo_bool_setting(ENABLE_MONGOC "Enable the build of libmongoc libraries (The MongoDB C database driver)")

build/cmake/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ add_subdirectory (make_dist)
22

33
set (build_cmake_MODULES
44
CheckSchedGetCPU.cmake
5+
GeneratePkgConfig.cmake
56
ResSearch.cmake
67
FindSASL2.cmake
78
FindSnappy.cmake

build/cmake/GeneratePkgConfig.cmake

Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
include_guard(GLOBAL)
2+
3+
include(GNUInstallDirs)
4+
5+
define_property(
6+
TARGET PROPERTY pkg_config_REQUIRES INHERITED
7+
BRIEF_DOCS "pkg-config 'Requires:' items"
8+
FULL_DOCS "Specify 'Requires:' items for the targets' pkg-config file"
9+
)
10+
define_property(
11+
TARGET PROPERTY pkg_config_NAME INHERITED
12+
BRIEF_DOCS "The 'Name' for pkg-config"
13+
FULL_DOCS "The 'Name' of the pkg-config target"
14+
)
15+
define_property(
16+
TARGET PROPERTY pkg_config_DESCRIPTION INHERITED
17+
BRIEF_DOCS "The 'Description' pkg-config property"
18+
FULL_DOCS "The 'Description' property to add to a target's pkg-config file"
19+
)
20+
define_property(
21+
TARGET PROPERTY pkg_config_VERSION INHERITED
22+
BRIEF_DOCS "The 'Version' pkg-config property"
23+
FULL_DOCS "The 'Version' property to add to a target's pkg-config file"
24+
)
25+
define_property(
26+
TARGET PROPERTY pkg_config_CFLAGS INHERITED
27+
BRIEF_DOCS "The 'Cflags' pkg-config property"
28+
FULL_DOCS "Set a list of options to add to a target's pkg-config file 'Cflags' field"
29+
)
30+
define_property(
31+
TARGET PROPERTY pkg_config_INCLUDE_DIRECTORIES INHERITED
32+
BRIEF_DOCS "Add -I options to the 'Cflags' pkg-config property"
33+
FULL_DOCS "Set a list of directories that will be added using -I for the 'Cflags' pkg-config field"
34+
)
35+
define_property(
36+
TARGET PROPERTY pkg_config_LIBS INHERITED
37+
BRIEF_DOCS "Add linker options to the 'Libs' pkg-config field"
38+
FULL_DOCS "Set a list of linker options that will joined in a string for the 'Libs' pkg-config field"
39+
)
40+
41+
# Given a string, escape any generator-expression-special characters
42+
function(_genex_escape out in)
43+
# Escape '>'
44+
string(REPLACE ">" "$<ANGLE-R>" str "${in}")
45+
# Escape "$"
46+
string(REPLACE "$" "$<1:$>" str "${str}")
47+
# Undo the escaping of the dollar for $<ANGLE-R>
48+
string(REPLACE "$<1:$><ANGLE-R>" "$<ANGLE-R>" str "${str}")
49+
# Escape ","
50+
string(REPLACE "," "$<COMMA>" str "${str}")
51+
# Escape ";"
52+
string(REPLACE ";" "$<SEMICOLON>" str "${str}")
53+
set("${out}" "${str}" PARENT_SCOPE)
54+
endfunction()
55+
56+
# Create a generator expression that ensures the given input generator expression
57+
# is evaluated within the context of the named target.
58+
function(_bind_genex_to_target out target genex)
59+
_genex_escape(escaped "${genex}")
60+
set("${out}" $<TARGET_GENEX_EVAL:${target},${escaped}> PARENT_SCOPE)
61+
endfunction()
62+
63+
#[==[
64+
Generate a pkg-config .pc file for the Given CMake target, and optionally a
65+
rule to install it::
66+
67+
generate_pkg_config(
68+
<target>
69+
[FILENAME <filename>]
70+
[LIBDIR <libdir>]
71+
[INSTALL [DESTINATION <dir>] [RENAME <filename>]]
72+
[CONDITION <cond>]
73+
)
74+
75+
The `<target>` must name an existing target. The following options are accepted:
76+
77+
FILENAME <filename>
78+
- The generated .pc file will have the given `<filename>`. This name *must*
79+
be only the filename, and not a qualified path. If omitted, the default
80+
filename is generated based on the target name. If using a multi-config
81+
generator, the default filename will include the name of the configuration
82+
for which it was generated.
83+
84+
LIBDIR <libdir>
85+
- Specify the subdirectory of the install prefix in which the target binary
86+
will live. If unspecified, uses `CMAKE_INSTALL_LIBDIR`, which comes from
87+
the GNUInstallDirs module, which has a default of `lib`.
88+
89+
INSTALL [DESTINATION <dir>] [RENAME <filename>]
90+
- Generate a rule to install the generated pkg-config file. This is better
91+
than using a `file(INSTALL)` on the generated file directly, since it
92+
ensures that the installed .pc file will have the correct install prefix
93+
value. The following additional arguments are also accepted:
94+
95+
DESTINATION <dir>
96+
- If provided, specify the *directory* (relative to the install-prefix)
97+
in which the generated file will be installed. If unspecified, the
98+
default destination is `<libdir>/pkgconfig`
99+
100+
RENAME <filename>
101+
- If provided, set the filename of the installed pkg-config file. If
102+
unspecified, the top-level `<filename>` will be used. (Note that the
103+
default top-level `<filename>` will include the configuration type
104+
when built/installed using a multi-config generator!)
105+
106+
CONDITION <cond>
107+
- The file will only be generated/installed if the condition `<cond>`
108+
results in the string "1" after evaluating generator expressions.
109+
110+
All named parameters accept generator expressions.
111+
112+
]==]
113+
function(mongo_generate_pkg_config target)
114+
# Collect some target properties:
115+
# The name:
116+
_genex_escape(proj_name "${PROJECT_NAME}")
117+
_genex_escape(proj_desc "${PROJECT_DESCRIPTION}")
118+
set(tgt_name $<TARGET_PROPERTY:pkg_config_NAME>)
119+
set(tgt_version $<TARGET_PROPERTY:pkg_config_VERSION>)
120+
set(tgt_desc $<TARGET_PROPERTY:pkg_config_DESCRIPTION>)
121+
string(CONCAT gx_name
122+
$<IF:$<STREQUAL:,${tgt_name}>,
123+
${proj_name},
124+
${tgt_name}>)
125+
# Version:
126+
string(CONCAT gx_version
127+
$<IF:$<STREQUAL:,${tgt_version}>,
128+
${PROJECT_VERSION},
129+
${tgt_version}>)
130+
# Description:
131+
string(CONCAT gx_desc
132+
$<IF:$<STREQUAL:,${tgt_desc}>,
133+
${proj_desc},
134+
${tgt_desc}>)
135+
136+
# Parse and validate arguments:
137+
cmake_parse_arguments(PARSE_ARGV 1 ARG "" "FILENAME;LIBDIR;CONDITION" "INSTALL")
138+
139+
# Compute the default FILENAME
140+
if(NOT DEFINED ARG_FILENAME)
141+
# No filename given. Pick a default:
142+
if(DEFINED CMAKE_CONFIGURATION_TYPES)
143+
# Multi-conf: We may want to generate more than one, so qualify the
144+
# filename with the configuration type:
145+
set(ARG_FILENAME "$<TARGET_FILE_BASE_NAME:${target}>-$<LOWER_CASE:$<CONFIG>>.pc")
146+
else()
147+
# Just generate a file based on the basename of the target:
148+
set(ARG_FILENAME "$<TARGET_FILE_BASE_NAME:${target}>.pc")
149+
endif()
150+
endif()
151+
152+
# The defalut CONDITION is just "1" (true)
153+
if(NOT DEFINED ARG_CONDITION)
154+
set(ARG_CONDITION 1)
155+
endif()
156+
_bind_genex_to_target(gx_cond ${target} "${ARG_CONDITION}")
157+
158+
# The default LIBDIR comes from GNUInstallDirs.cmake
159+
if(NOT ARG_LIBDIR)
160+
set(ARG_LIBDIR "${CMAKE_INSTALL_LIBDIR}")
161+
endif()
162+
_bind_genex_to_target(gx_libdir ${target} "${ARG_LIBDIR}")
163+
164+
# Evaluate the filename genex in the context of the target:
165+
_bind_genex_to_target(gx_filename ${target} "${ARG_FILENAME}")
166+
if(IS_ABSOLUTE "${ARG_FILENAME}")
167+
set(gx_output "${gx_filename}")
168+
else()
169+
get_filename_component(gx_output "${CMAKE_CURRENT_BINARY_DIR}/${gx_filename}" ABSOLUTE)
170+
endif()
171+
172+
# Generate the content of the file:
173+
_generate_pkg_config_content(content
174+
NAME "${gx_name}"
175+
VERSION "${gx_version}"
176+
DESCRIPTION "${gx_desc}"
177+
PREFIX "%INSTALL_PLACEHOLDER%"
178+
LIBDIR "${gx_libdir}"
179+
GENEX_TARGET "${target}"
180+
)
181+
_bind_genex_to_target(gx_content ${target} "${content}")
182+
string(REPLACE "%INSTALL_PLACEHOLDER%" "${CMAKE_INSTALL_PREFIX}" gx_with_prefix "${gx_content}")
183+
# Now, generate the file:
184+
file(GENERATE
185+
OUTPUT "${gx_output}"
186+
CONTENT "${gx_with_prefix}"
187+
CONDITION "${gx_cond}")
188+
if(NOT "INSTALL" IN_LIST ARGN)
189+
# Nothing more to do here.
190+
return()
191+
endif()
192+
193+
# Installation handling:
194+
# Use file(GENERATE) to generate a temporary file to be picked up at install-time.
195+
# (For some reason, injecting the content directly into install(CODE) fails in corner cases)
196+
set(gx_tmpfile "${CMAKE_CURRENT_BINARY_DIR}/_pkgconfig/${target}-$<LOWER_CASE:$<CONFIG>>-for-install.txt")
197+
file(GENERATE OUTPUT "${gx_tmpfile}"
198+
CONTENT "${gx_content}"
199+
CONDITION "${gx_cond}")
200+
# Parse the install args that we will inspect:
201+
cmake_parse_arguments(inst "" "DESTINATION;RENAME" "" ${ARG_INSTALL})
202+
if(NOT DEFINED inst_DESTINATION)
203+
# Install based on the libdir:
204+
set(inst_DESTINATION "${gx_libdir}/pkgconfig")
205+
endif()
206+
if(NOT DEFINED inst_RENAME)
207+
set(inst_RENAME "${ARG_FILENAME}")
208+
endif()
209+
# install(CODE) will write a simple temporary file:
210+
set(inst_tmp "${CMAKE_CURRENT_BINARY_DIR}/${target}-pkg-config-tmp.txt")
211+
_genex_escape(esc_cond "${ARG_CONDITION}")
212+
string(CONFIGURE [==[
213+
$<@gx_cond@:
214+
# Installation of pkg-config for target @target@
215+
message(STATUS "Generating pkg-config file: @inst_RENAME@")
216+
file(READ [[@gx_tmpfile@]] content)
217+
# Insert the install prefix:
218+
string(REPLACE "%INSTALL_PLACEHOLDER%" "${CMAKE_INSTALL_PREFIX}" content "${content}")
219+
# Write it before installing again:
220+
file(WRITE [[@inst_tmp@]] "${content}")
221+
>
222+
$<$<NOT:@gx_cond@>:
223+
# Installation was disabled for this generation.
224+
message(STATUS "Skipping install of file [@inst_RENAME@]: Disabled by CONDITION “@esc_cond@”")
225+
>
226+
]==] code @ONLY)
227+
install(CODE "${code}")
228+
_bind_genex_to_target(gx_dest ${target} "${inst_DESTINATION}")
229+
_bind_genex_to_target(gx_rename ${target} "${inst_RENAME}")
230+
# Wrap the filename to install with the same condition used to generate it. If the condition
231+
# is not met, then the FILES list will be empty, and nothing will be installed.
232+
install(FILES "$<${gx_cond}:${inst_tmp}>"
233+
DESTINATION ${gx_dest}
234+
RENAME ${gx_rename}
235+
${inst_UNPARSED_ARGUMENTS})
236+
endfunction()
237+
238+
# Generates the actual content of a .pc file.
239+
function(_generate_pkg_config_content out)
240+
cmake_parse_arguments(PARSE_ARGV 1 ARG "" "PREFIX;NAME;VERSION;DESCRIPTION;GENEX_TARGET;LIBDIR" "")
241+
if(ARG_UNPARSED_ARGUMENTS)
242+
message(FATAL_ERROR "Unknown arguments: ${ARG_UNPARSED_ARGUMENTS}")
243+
endif()
244+
set(content)
245+
string(APPEND content
246+
"# pkg-config .pc file generated by CMake ${CMAKE_VERSION} for ${ARG_NAME}-${ARG_VERSION}. DO NOT EDIT!\n"
247+
"prefix=${ARG_PREFIX}\n"
248+
"exec_prefix=\${prefix}\n"
249+
"libdir=\${exec_prefix}/${gx_libdir}\n"
250+
"\n"
251+
"Name: ${ARG_NAME}\n"
252+
"Description: ${ARG_DESCRIPTION}\n"
253+
"Version: ${ARG_VERSION}"
254+
)
255+
# Add Requires:
256+
set(requires_joiner "\nRequires: ")
257+
set(gx_requires $<GENEX_EVAL:$<TARGET_PROPERTY:pkg_config_REQUIRES>>)
258+
set(has_requires $<NOT:$<STREQUAL:,${gx_requires}>>)
259+
string(APPEND content "$<${has_requires}:${requires_joiner}$<JOIN:${gx_requires},${requires_joiner}>>\n")
260+
string(APPEND content "\n")
261+
# Add "Libs:"
262+
set(libs)
263+
# Link options:
264+
set(gx_libs
265+
"-L\${libdir}"
266+
"-l$<TARGET_PROPERTY:OUTPUT_NAME>"
267+
$<GENEX_EVAL:$<TARGET_PROPERTY:pkg_config_LIBS>>
268+
$<TARGET_PROPERTY:INTERFACE_LINK_OPTIONS>
269+
)
270+
string(APPEND libs "$<JOIN:${gx_libs};${gx_linkopts}, >")
271+
272+
# Cflags:
273+
set(cflags)
274+
set(gx_flags
275+
$<REMOVE_DUPLICATES:$<GENEX_EVAL:$<TARGET_PROPERTY:pkg_config_CFLAGS>>>
276+
$<REMOVE_DUPLICATES:$<TARGET_PROPERTY:INTERFACE_COMPILE_OPTIONS>>
277+
)
278+
string(APPEND cflags "$<JOIN:${gx_flags}, >")
279+
# Definitions:
280+
set(gx_defs $<REMOVE_DUPLICATES:$<TARGET_PROPERTY:INTERFACE_COMPILE_DEFINITIONS>>)
281+
set(has_defs $<NOT:$<STREQUAL:,${gx_defs}>>)
282+
set(def_joiner " -D")
283+
string(APPEND cflags $<${has_defs}:${def_joiner}$<JOIN:${gx_defs},${def_joiner}>>)
284+
# Includes:
285+
set(gx_inc $<GENEX_EVAL:$<TARGET_PROPERTY:pkg_config_INCLUDE_DIRECTORIES>>)
286+
set(gx_inc "$<REMOVE_DUPLICATES:${gx_inc}>")
287+
set(gx_abs_inc "$<FILTER:${gx_inc},INCLUDE,^/>")
288+
set(gx_rel_inc "$<FILTER:${gx_inc},EXCLUDE,^/>")
289+
set(has_abs_inc $<NOT:$<STREQUAL:,${gx_abs_inc}>>)
290+
set(has_rel_inc $<NOT:$<STREQUAL:,${gx_rel_inc}>>)
291+
string(APPEND cflags $<${has_rel_inc}: " -I\${prefix}/"
292+
$<JOIN:${gx_rel_inc}, " -I\${prefix}/" >>
293+
$<${has_abs_inc}: " -I"
294+
$<JOIN:${gx_abs_inc}, " -I" >>)
295+
string(APPEND content "Libs: ${libs}\n")
296+
string(APPEND content "Cflags: ${cflags}\n")
297+
set("${out}" "${content}" PARENT_SCOPE)
298+
endfunction()

build/cmake/ResSearch.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
include(CheckSymbolExists)
22
include(CMakePushCheckState)
33

4-
cmake_push_check_state(RESET)
4+
cmake_push_check_state()
55

66
# The name of the library that performs name resolution, suitable for giving to the "-l" link flag
77
set(RESOLVE_LIB_NAME)

src/libbson/CMakeLists.txt

Lines changed: 11 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
cmake_minimum_required (VERSION 3.1)
1+
cmake_minimum_required (VERSION 3.15)
22

33
project (libbson C)
44

@@ -237,6 +237,7 @@ target_include_directories (
237237
)
238238
set_target_properties (bson_shared PROPERTIES VERSION 0.0.0 SOVERSION 0)
239239
set_target_properties (bson_shared PROPERTIES OUTPUT_NAME "${BSON_OUTPUT_BASENAME}-${BSON_API_VERSION}")
240+
mongo_generate_pkg_config (bson_shared FILENAME libbson-1.0.pc INSTALL)
240241

241242
if (ENABLE_APPLE_FRAMEWORK)
242243
set_target_properties(bson_shared PROPERTIES
@@ -334,6 +335,9 @@ if (MONGOC_ENABLE_STATIC_BUILD)
334335
# gethostbyname
335336
target_link_libraries (bson_static ws2_32)
336337
endif ()
338+
if(MONGOC_ENABLE_STATIC_INSTALL)
339+
mongo_generate_pkg_config(bson_static FILENAME libbson-static-1.0.pc INSTALL)
340+
endif()
337341
endif ()
338342

339343
function (add_example bin src)
@@ -378,6 +382,12 @@ install (
378382
INCLUDES DESTINATION ${BSON_HEADER_INSTALL_DIR}
379383
FRAMEWORK DESTINATION ${CMAKE_INSTALL_BINDIR}
380384
)
385+
set_target_properties(${TARGETS_TO_INSTALL} PROPERTIES
386+
pkg_config_NAME libbson
387+
pkg_config_DESCRIPTION "The libbson BSON serialization library."
388+
pkg_config_VERSION "${BSON_VERSION}"
389+
)
390+
set_property(TARGET ${TARGETS_TO_INSTALL} APPEND PROPERTY pkg_config_INCLUDE_DIRECTORIES "${BSON_HEADER_INSTALL_DIR}")
381391

382392
install (
383393
FILES ${HEADERS}
@@ -408,35 +418,6 @@ foreach (_lib ${BSON_SYSTEM_LIBRARIES})
408418
set (LIBBSON_LIBRARIES "${LIBBSON_LIBRARIES} ${_lib}")
409419
endforeach ()
410420

411-
set (VERSION "${BSON_VERSION}")
412-
set (prefix "${CMAKE_INSTALL_PREFIX}")
413-
set (libdir "\${prefix}/${CMAKE_INSTALL_LIBDIR}")
414-
configure_file (
415-
${CMAKE_CURRENT_SOURCE_DIR}/src/libbson-1.0.pc.in
416-
${CMAKE_CURRENT_BINARY_DIR}/src/libbson-1.0.pc
417-
@ONLY)
418-
419-
install (
420-
FILES
421-
${CMAKE_CURRENT_BINARY_DIR}/src/libbson-1.0.pc
422-
DESTINATION
423-
${CMAKE_INSTALL_LIBDIR}/pkgconfig
424-
)
425-
426-
if (MONGOC_ENABLE_STATIC_INSTALL)
427-
configure_file (
428-
${CMAKE_CURRENT_SOURCE_DIR}/src/libbson-static-1.0.pc.in
429-
${CMAKE_CURRENT_BINARY_DIR}/src/libbson-static-1.0.pc
430-
@ONLY)
431-
432-
install (
433-
FILES
434-
${CMAKE_CURRENT_BINARY_DIR}/src/libbson-static-1.0.pc
435-
DESTINATION
436-
${CMAKE_INSTALL_LIBDIR}/pkgconfig
437-
)
438-
endif ()
439-
440421
include (CMakePackageConfigHelpers)
441422
set (INCLUDE_INSTALL_DIRS "${BSON_HEADER_INSTALL_DIR}")
442423
set (LIBRARY_INSTALL_DIRS ${CMAKE_INSTALL_LIBDIR})

0 commit comments

Comments
 (0)