Skip to content

Commit

Permalink
pkg-config file: fix handling of variable-relative paths
Browse files Browse the repository at this point in the history
In order to handle cross compilation and other concerns, pkg-config
files support defining includedir/libdir relative to prefix and perform
deferred expansion. For this reason, the expected value of each is:

${prefix}/lib
${prefix}/include

or similar.

This may or may not work depending on how the standard directories are
installed:

- autotools

  all directory variables must be specified by absolute path. However,
  those variables use the same format as pkg-config to do expansions, so
  it is possible to pass --libdir='${prefix}/lib' and generate correct
  pkg-config files

- meson

  all directory variables can be specified by either relative or
  absolute path. For absolute paths, if they fit inside prefix they are
  converted to relative paths. There is also a builtin `join_paths`
  function that correctly handles path joining for both relative and
  absolute paths. The builtin pkg-config generator always generates
  correct pkg-config files no matter how you specify directory
  variables, and it is possible to manually define paths as:
  join_paths('${prefix}', get_option('libdir'))

- cmake

  all directory variables can be specified by either relative or
  absolute path. No post-processing is done, so CMAKE_INSTALL_LIBDIR may
  be relative or absolute, but CMAKE_INSTALL_FULL_LIBDIR is always
  absolute. If you must have a relative path, you cannot get one.

Unfortunately, cmake has neither of the coping mechanisms of meson or
autotools. So some manual work is needed in order to generate correct
pkg-config files. The following assumption must be made:

- this will only be correct if the user configures cmake using relative
  paths

We also need a shared third-party function to reimplement join_paths
semantics, available from:
https://github.com/jtojnar/cmake-snips#concatenating-paths-when-building-pkg-config-files

Using this we can guarantee that directory variables are always expanded
to one of two things:

- a "technically incorrect" full path such as `/usr/lib` if the user
  configured with full paths

- a spec compliant path such as `${prefix}/lib` if the user configured
  with relative paths

Although this isn't always perfect, it allows -- like autotools --
having fully correct pkg-config files as long as the user configures the
build system the "correct" way (relative paths), and in the event that a
sub-optimal configuration is used (full paths) a working but sub-optimal
pkg-config file is generated.

This fixes the case where previously, if a user configured with full
paths the generated pkg-config file ended up with directory variables
such as:

prefix=/usr
libdir=${prefix}/usr/lib
includedir=${prefix}/usr/include

Using a proper join_paths() function guarantees that if the
CMAKE_INSTALL_* variables are absolute paths already, the `${prefix}` is
not prepended to them.
  • Loading branch information
eli-schwartz authored and mikeb01 committed Mar 6, 2022
1 parent 298cc53 commit b083efd
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 2 deletions.
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ project(hdr_histogram
DESCRIPTION "C port of the HdrHistogram"
HOMEPAGE_URL "http://hdrhistogram.github.io/HdrHistogram/")

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")

include(GNUInstallDirs)
include(CMakePackageConfigHelpers)

Expand Down Expand Up @@ -94,6 +96,11 @@ install(
set(CPACK_GENERATOR "TGZ")
include(CPack)

include(JoinPaths)

join_paths(includedir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
join_paths(libdir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_LIBDIR}")

if(${ZLIB_FOUND})
set(PC_REQUIRES_PRIVATE_ZLIB "zlib")
else()
Expand Down
23 changes: 23 additions & 0 deletions cmake/JoinPaths.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# This module provides function for joining paths
# known from most languages
#
# SPDX-License-Identifier: (MIT OR CC0-1.0)
# Copyright 2020 Jan Tojnar
# https://github.com/jtojnar/cmake-snips
#
# Modelled after Python’s os.path.join
# https://docs.python.org/3.7/library/os.path.html#os.path.join
# Windows not supported
function(join_paths joined_path first_path_segment)
set(temp_path "${first_path_segment}")
foreach(current_segment IN LISTS ARGN)
if(NOT ("${current_segment}" STREQUAL ""))
if(IS_ABSOLUTE "${current_segment}")
set(temp_path "${current_segment}")
else()
set(temp_path "${temp_path}/${current_segment}")
endif()
endif()
endforeach()
set(${joined_path} "${temp_path}" PARENT_SCOPE)
endfunction()
4 changes: 2 additions & 2 deletions hdr_histogram.pc.in
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
prefix=@CMAKE_INSTALL_PREFIX@
libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
libdir=@libdir_for_pc_file@
includedir=@includedir_for_pc_file@

Name: @PROJECT_NAME@
Description: @CMAKE_PROJECT_DESCRIPTION@
Expand Down

0 comments on commit b083efd

Please sign in to comment.