Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- jrl_release: add `ConanFileVersionExtractor` by @arntanguy
- jrl_release: add `--check-version --check-tag vX.Y.Z` by @arntanguy
- jrl_release: add `DebianChangelogVersionExtractor` by @arntanguy
- jrl: change jrl_configure_default_install_dirs() to macro to make GNUInstallDirs in caller's scope by @ahoarau

## [2.1.0] - 2026-07-03

Expand Down
6 changes: 5 additions & 1 deletion v2/docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,13 +219,17 @@ jrl_target_set_output_directory(my_python_module_target OUTPUT_DIRECTORY ${CMAKE
jrl_configure_default_install_dirs()
```

**Type:** function
**Type:** macro


### Description
Configures the default install directories using GNUInstallDirs (bin, lib, include, etc.).
Works on all platforms.

Must be called directly from a project's `CMakeLists.txt`, not wrapped in a `function()`:
`CMAKE_INSTALL_DOCDIR`, `DATADIR`, `MANDIR`, `INFODIR`, `LOCALEDIR` and every
`CMAKE_INSTALL_FULL_*` are not cache entries and would be lost when the function returns.


### Arguments
None
Expand Down
35 changes: 29 additions & 6 deletions v2/modules/jrl.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -796,13 +796,17 @@ endfunction()
jrl_configure_default_install_dirs()
```

**Type:** function
**Type:** macro


### Description
Configures the default install directories using GNUInstallDirs (bin, lib, include, etc.).
Works on all platforms.

Must be called directly from a project's `CMakeLists.txt`, not wrapped in a `function()`:
`CMAKE_INSTALL_DOCDIR`, `DATADIR`, `MANDIR`, `INFODIR`, `LOCALEDIR` and every
`CMAKE_INSTALL_FULL_*` are not cache entries and would be lost when the function returns.


### Arguments
None
Expand All @@ -813,19 +817,37 @@ jrl_configure_default_install_dirs()
jrl_configure_default_install_dirs()
```
#]============================================================================]
function(jrl_configure_default_install_dirs)
macro(jrl_configure_default_install_dirs)
if(DEFINED CMAKE_CURRENT_FUNCTION)
message(
FATAL_ERROR
"jrl_configure_default_install_dirs() must be called directly from a CMakeLists.txt, not from inside function '${CMAKE_CURRENT_FUNCTION}()'.
The GNUInstallDirs variables that are not cache entries (CMAKE_INSTALL_DOCDIR, DATADIR, MANDIR,
INFODIR, LOCALEDIR and all CMAKE_INSTALL_FULL_*) would be lost when that function returns.
"
)
endif()

# Prevent the following warning on pure-cmake projects (i.e. defined with LANGUAGES NONE, like jrl-cmakemodules):
# "Unable to determine default CMAKE_INSTALL_LIBDIR directory because no target architecture is known.
# Please enable at least one language before including GNUInstallDirs"
# ref: https://github.com/Kitware/CMake/blob/v4.2.3/Modules/GNUInstallDirs.cmake#L434C8-L435C75
# issue: https://gitlab.kitware.com/cmake/cmake/-/issues/23461

if(NOT DEFINED CMAKE_SIZEOF_VOID_P)
if(DEFINED CMAKE_SIZEOF_VOID_P)
set(_cmake_sizeof_already_defined false)
else()
set(_cmake_sizeof_already_defined true)
set(CMAKE_SIZEOF_VOID_P 0)
endif()

include(GNUInstallDirs)
endfunction()

# Do not leak the placeholder: a defined-but-0 value is worse than an undefined one.
if(_cmake_sizeof_already_defined)
unset(CMAKE_SIZEOF_VOID_P)
endif()
unset(_cmake_sizeof_already_defined)
endmacro()

#[============================================================================[
# `jrl_configure_default_install_prefix`
Expand Down Expand Up @@ -939,8 +961,9 @@ jrl_configure_defaults()
macro(jrl_configure_defaults)
jrl_configure_default_build_type(Release)
jrl_configure_default_binary_dirs()
jrl_configure_default_install_dirs()
# Before install_dirs: GNUInstallDirs derives CMAKE_INSTALL_FULL_* from the prefix, once.
jrl_configure_default_install_prefix(${CMAKE_BINARY_DIR}/install)
jrl_configure_default_install_dirs()
jrl_configure_copy_compile_commands_in_source_dir()
jrl_configure_uninstall_target()
endmacro()
Expand Down
1 change: 1 addition & 0 deletions v2/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,4 @@ add_subdirectory(print_dependencies_summary)
add_subdirectory(export_package_control)
add_subdirectory(target_headers_relative)
add_subdirectory(output_dirs)
add_subdirectory(gnu_install_dirs)
1 change: 1 addition & 0 deletions v2/tests/gnu_install_dirs/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add_cmake_test(NAME gid-project DEPENDS jrl-cmakemodules)
6 changes: 6 additions & 0 deletions v2/tests/gnu_install_dirs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# gnu_install_dirs

Verifies that `jrl_configure_defaults()` leaves every `GNUInstallDirs` variable usable in the
caller's scope, including `CMAKE_INSTALL_DOCDIR`, `DATADIR`, `MANDIR`, `INFODIR`, `LOCALEDIR`
and all the `CMAKE_INSTALL_FULL_*`, which are not cache entries and are therefore lost if
`GNUInstallDirs` is included from inside a `function()`.
61 changes: 61 additions & 0 deletions v2/tests/gnu_install_dirs/gid-project/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
cmake_minimum_required(VERSION 3.22)

project(gid-project VERSION 1.0.0 LANGUAGES CXX)

find_package(jrl-cmakemodules 2.0.0 CONFIG REQUIRED)

jrl_configure_defaults()

# GNUInstallDirs only creates cache entries for its root dirs (BINDIR, LIBDIR, ...).
# The derived ones (DATADIR, DOCDIR, MANDIR, INFODIR, LOCALEDIR) and every
# CMAKE_INSTALL_FULL_* are plain variables, lost if GNUInstallDirs is included
# from inside a function(). They must all be usable in the caller's scope.
set(expected_install_dirs
BINDIR
SBINDIR
LIBEXECDIR
SYSCONFDIR
SHAREDSTATEDIR
LOCALSTATEDIR
LIBDIR
INCLUDEDIR
OLDINCLUDEDIR
DATAROOTDIR
DATADIR
INFODIR
LOCALEDIR
MANDIR
DOCDIR
)

foreach(dir IN LISTS expected_install_dirs)
foreach(var CMAKE_INSTALL_${dir} CMAKE_INSTALL_FULL_${dir})
if(NOT DEFINED ${var})
message(FATAL_ERROR "${var} is not defined after jrl_configure_defaults()")
endif()
if(${var} STREQUAL "")
message(FATAL_ERROR "${var} is empty after jrl_configure_defaults()")
endif()
endforeach()
message(
STATUS
"CMAKE_INSTALL_${dir}=${CMAKE_INSTALL_${dir}} (full: ${CMAKE_INSTALL_FULL_${dir}})"
)
endforeach()

if(NOT CMAKE_INSTALL_DOCDIR STREQUAL "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}")
message(
FATAL_ERROR
"Expected CMAKE_INSTALL_DOCDIR to be '${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}', got: '${CMAKE_INSTALL_DOCDIR}'"
)
endif()

file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test.txt" "OK\n")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/test.txt" DESTINATION ${CMAKE_INSTALL_DOCDIR})

enable_testing()

add_test(
NAME "gnu_install_dirs: test.txt is installed in CMAKE_INSTALL_DOCDIR"
COMMAND ${CMAKE_COMMAND} -E cat "${CMAKE_INSTALL_FULL_DOCDIR}/test.txt"
)
30 changes: 30 additions & 0 deletions v2/tests/gnu_install_dirs/gid-project/pixi.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[workspace]
name = "gid-project"
version = "1.0.0"
channels = ["conda-forge"]
platforms = ["osx-arm64", "osx-64", "linux-64", "linux-aarch64", "win-64"]
preview = ["pixi-build"]

[dependencies]
cxx-compiler = "*"
cmake = ">=3.22"
ninja = "*"
jrl-cmakemodules = { path = "../../../../" }

[tasks]
clear = { cmd = "rm -rf build" }
configure = { cmd = "cmake --log-level=DEBUG -G Ninja -S . -B build" }
build = { cmd = "cmake --build build" }
install = { cmd = "cmake --install build" }
ctest = { cmd = "ctest --test-dir build --output-on-failure --no-tests=ignore" }
test = { depends-on = ["clear", "configure", "build", "install", "ctest"] }

[package]
name = { workspace = true }
version = { workspace = true }

[package.host-dependencies]
jrl-cmakemodules = { path = "../../../.." }

[package.build]
backend = { name = "pixi-build-cmake", version = "*" }
6 changes: 6 additions & 0 deletions v2/tests/gnu_install_dirs/pixi.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[workspace]
channels = ["conda-forge"]
platforms = ["linux-64", "linux-aarch64", "osx-arm64", "osx-64", "win-64"]

[tasks]
test = { cmd = "pixi run test", cwd = "gid-project" }
2 changes: 2 additions & 0 deletions v2/tests/pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ test_header_visibility = { cmd = "pixi run test", cwd = "header_visibility" }
test_export_package_control = { cmd = "pixi run test", cwd = "export_package_control" }
test_target_headers_relative = { cmd = "pixi run test", cwd = "target_headers_relative" }
test_output_dirs = { cmd = "pixi run test", cwd = "output_dirs" }
test_gnu_install_dirs = { cmd = "pixi run test", cwd = "gnu_install_dirs" }

test = { depends-on = [
"test_find_modules",
Expand All @@ -47,4 +48,5 @@ test = { depends-on = [
"test_export_package_control",
"test_target_headers_relative",
"test_output_dirs",
"test_gnu_install_dirs",
] }
Loading