Skip to content

Commit 974fb59

Browse files
authored
Update dependency handling logic in meson and CMake (#9)
- allow meson to find dependencies before falling back to subprojects - install module files in meson builds - add custom CMake finder for mctc-lib - add CMake macro to find (cmake/pkgconf) or include (subproject/fetch) dependencies
1 parent 0184acc commit 974fb59

9 files changed

Lines changed: 238 additions & 39 deletions

File tree

CMakeLists.txt

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,18 @@ project(
2626
# Follow GNU conventions for installing directories
2727
include(GNUInstallDirs)
2828

29-
# Collect subprojects
30-
set(lib-deps)
31-
add_subdirectory("subprojects" EXCLUDE_FROM_ALL)
32-
3329
# General configuration information
3430
add_subdirectory("config")
3531

32+
# Collect subprojects
33+
if(NOT TARGET "mctc-lib::mctc-lib")
34+
find_package("mctc-lib")
35+
endif()
36+
set(
37+
lib-deps
38+
"mctc-lib::mctc-lib"
39+
)
40+
3641
# Collect source of the project
3742
set(srcs)
3843
add_subdirectory("src")
@@ -61,6 +66,7 @@ target_include_directories(
6166
PUBLIC
6267
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
6368
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
69+
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${module-dir}>
6470
)
6571

6672
# Add example application
@@ -88,7 +94,7 @@ install(
8894
install(
8995
DIRECTORY
9096
"${CMAKE_CURRENT_BINARY_DIR}/include/"
91-
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}"
97+
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${module-dir}"
9298
)
9399
# Package license files
94100
install(

config/CMakeLists.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,19 @@
1515

1616
option(BUILD_SHARED_LIBS "Whether the libraries built should be shared" FALSE)
1717

18+
if(NOT DEFINED "${PROJECT_NAME}-dependeny-method")
19+
set(
20+
"${PROJECT_NAME}-dependency-method"
21+
"subproject" "cmake" "pkgconf" "fetch"
22+
)
23+
endif()
24+
25+
set(
26+
module-dir
27+
"${PROJECT_NAME}/${CMAKE_Fortran_COMPILER_ID}-${CMAKE_Fortran_COMPILER_VERSION}"
28+
)
29+
set(module-dir "${module-dir}" PARENT_SCOPE)
30+
1831
# Set build type as CMake does not provide defaults
1932
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
2033
set(
@@ -28,6 +41,14 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
2841
)
2942
endif()
3043

44+
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
45+
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" PARENT_SCOPE)
46+
install(
47+
DIRECTORY
48+
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/"
49+
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
50+
)
51+
3152
include(CMakePackageConfigHelpers)
3253
configure_package_config_file(
3354
"${CMAKE_CURRENT_SOURCE_DIR}/template.cmake"
Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,27 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515

16-
# Include the mctc-lib project
17-
if(NOT TARGET mctc-lib)
18-
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/mctc-lib/CMakeLists.txt)
19-
add_subdirectory("mctc-lib")
16+
set(_lib "mctc-lib")
17+
set(_pkg "MCTCLIB")
18+
set(_url "https://github.com/grimme-lab/mctc-lib")
19+
20+
if(NOT DEFINED "${_pkg}_FIND_METHOD")
21+
if(DEFINED "${PROJECT_NAME}-dependency-method")
22+
set("${_pkg}_FIND_METHOD" "${${PROJECT_NAME}-dependency-method}")
2023
else()
21-
set("mctc-lib-url" "https://github.com/grimme-lab/mctc-lib")
22-
message(STATUS "Retrieving mctc-lib from ${mctc-lib-url}")
23-
include(FetchContent)
24-
FetchContent_Declare(
25-
"mctc-lib"
26-
GIT_REPOSITORY "${mctc-lib-url}"
27-
GIT_TAG "HEAD"
28-
)
29-
FetchContent_MakeAvailable("mctc-lib")
24+
set("${_pkg}_FIND_METHOD" "cmake" "pkgconf" "subproject" "fetch")
3025
endif()
26+
set("_${_pkg}_FIND_METHOD")
3127
endif()
3228

33-
list(
34-
APPEND lib-deps
35-
"mctc-lib"
36-
)
37-
set(lib-deps "${lib-deps}" PARENT_SCOPE)
29+
include("${CMAKE_CURRENT_LIST_DIR}/mstore-utils.cmake")
30+
31+
mstore_find_package("${_lib}" "${${_pkg}_FIND_METHOD}" "${_url}")
32+
33+
if(DEFINED "_${_pkg}_FIND_METHOD")
34+
unset("${_pkg}_FIND_METHOD")
35+
unset("_${_pkg}_FIND_METHOD")
36+
endif()
37+
unset(_lib)
38+
unset(_pkg)
39+
unset(_url)

config/cmake/mstore-utils.cmake

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# This file is part of mstore.
2+
# SPDX-Identifier: Apache-2.0
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
# Handling of subproject dependencies
17+
macro(
18+
"mstore_find_package"
19+
package
20+
methods
21+
url
22+
)
23+
string(TOLOWER "${package}" _pkg_lc)
24+
string(TOUPPER "${package}" _pkg_uc)
25+
26+
foreach(method in ITEMS ${methods})
27+
28+
if(TARGET "${package}::${package}")
29+
break()
30+
endif()
31+
32+
if("${method}" STREQUAL "cmake")
33+
message(STATUS "${package}: Find installed package")
34+
find_package("${package}" CONFIG)
35+
if("${package}_FOUND")
36+
message(STATUS "${package}: Found installed package")
37+
break()
38+
endif()
39+
endif()
40+
41+
if("${method}" STREQUAL "pkgconf")
42+
find_package(PkgConfig QUIET)
43+
pkg_check_modules("${_pkg_uc}" QUIET "${package}")
44+
if("${_pkg_uc}_FOUND")
45+
message(STATUS "Found ${package} via pkg-config")
46+
47+
add_library("${package}::${package}" INTERFACE IMPORTED)
48+
target_link_libraries(
49+
"${package}::${package}"
50+
INTERFACE
51+
"${${_pkg_uc}_LINK_LIBRARIES}"
52+
)
53+
target_include_directories(
54+
"${package}::${package}"
55+
INTERFACE
56+
"${${_pkg_uc}_INCLUDE_DIRS}"
57+
)
58+
break()
59+
endif()
60+
endif()
61+
62+
if("${method}" STREQUAL "subproject")
63+
set("${_pkg_uc}_SOURCE_DIR" "${PROJECT_SOURCE_DIR}/subprojects/${package}")
64+
set("${_pkg_uc}_BINARY_DIR" "${PROJECT_BINARY_DIR}/subprojects/${package}")
65+
if(EXISTS "${${_pkg_uc}_SOURCE_DIR}/CMakeLists.txt")
66+
message(STATUS "Include ${package} from subprojects")
67+
add_subdirectory(
68+
"${${_pkg_uc}_SOURCE_DIR}"
69+
"${${_pkg_uc}_BINARY_DIR}"
70+
)
71+
72+
add_library("${package}::${package}" INTERFACE IMPORTED)
73+
target_link_libraries("${package}::${package}" INTERFACE "${package}")
74+
75+
# We need the module directory in the subproject before we finish the configure stage
76+
if(NOT EXISTS "${${_pkg_uc}_BINARY_DIR}/include")
77+
make_directory("${${_pkg_uc}_BINARY_DIR}/include")
78+
endif()
79+
80+
break()
81+
endif()
82+
endif()
83+
84+
if("${method}" STREQUAL "fetch")
85+
message(STATUS "Retrieving ${package} from ${url}")
86+
include(FetchContent)
87+
FetchContent_Declare(
88+
"${_pkg_lc}"
89+
GIT_REPOSITORY "${url}"
90+
GIT_TAG "HEAD"
91+
)
92+
FetchContent_MakeAvailable("${_pkg_lc}")
93+
94+
add_library("${package}::${package}" INTERFACE IMPORTED)
95+
target_link_libraries("${package}::${package}" INTERFACE "${package}")
96+
97+
# We need the module directory in the subproject before we finish the configure stage
98+
FetchContent_GetProperties("${_pkg_lc}" BINARY_DIR "${_pkg_uc}_BINARY_DIR")
99+
if(NOT EXISTS "${${_pkg_uc}_BINARY_DIR}/include")
100+
make_directory("${${_pkg_uc}_BINARY_DIR}/include")
101+
endif()
102+
103+
break()
104+
endif()
105+
106+
endforeach()
107+
108+
unset(_pkg_lc)
109+
unset(_pkg_uc)
110+
111+
if(NOT TARGET "${package}::${package}")
112+
message(FATAL_ERROR "Could not find dependency ${package}")
113+
endif()
114+
115+
endmacro()

config/install-mod.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#!/usr/bin/env python
2+
# This file is part of mstore.
3+
# SPDX-Identifier: Apache-2.0
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
from os import environ, listdir, makedirs
18+
from os.path import join, isdir, exists
19+
from sys import argv
20+
from shutil import copy
21+
22+
build_dir = environ["MESON_BUILD_ROOT"]
23+
if "MESON_INSTALL_DESTDIR_PREFIX" in environ:
24+
install_dir = environ["MESON_INSTALL_DESTDIR_PREFIX"]
25+
else:
26+
install_dir = environ["MESON_INSTALL_PREFIX"]
27+
28+
include_dir = argv[1] if len(argv) > 1 else "include"
29+
module_dir = join(install_dir, include_dir)
30+
31+
modules = []
32+
for d in listdir(build_dir):
33+
bd = join(build_dir, d)
34+
if isdir(bd):
35+
for f in listdir(bd):
36+
if f.endswith(".mod"):
37+
modules.append(join(bd, f))
38+
39+
if not exists(module_dir):
40+
makedirs(module_dir)
41+
42+
for mod in modules:
43+
print("Installing", mod, "to", module_dir)
44+
copy(mod, module_dir)

config/meson.build

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,20 +43,22 @@ if get_option('openmp')
4343
endif
4444

4545
# Create the tool chain library as subproject
46-
mctc_prj = subproject(
47-
'mctc-lib',
48-
version: '>=0.1',
49-
default_options: [
50-
'default_library=static',
51-
],
52-
)
53-
mctc_dep = mctc_prj.get_variable('mctc_dep')
54-
lib_deps += mctc_dep
55-
inc_dirs += mctc_prj.get_variable('mctc_inc')
56-
57-
if install
58-
install_data(
59-
mctc_prj.get_variable('mctc_lic'),
60-
install_dir: get_option('datadir')/'licenses'/meson.project_name()/'mctc-lib'
46+
mctc_dep = dependency('mctc-lib', required: false)
47+
if not mctc_dep.found()
48+
mctc_prj = subproject(
49+
'mctc-lib',
50+
version: '>=0.2',
51+
default_options: [
52+
'default_library=static',
53+
],
6154
)
55+
mctc_dep = mctc_prj.get_variable('mctc_dep')
56+
57+
if install
58+
install_data(
59+
mctc_prj.get_variable('mctc_lic'),
60+
install_dir: get_option('datadir')/'licenses'/meson.project_name()/'mctc-lib'
61+
)
62+
endif
6263
endif
64+
lib_deps += mctc_dep

config/template.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
@PACKAGE_INIT@
22

3+
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
4+
35
if(NOT TARGET "@PROJECT_NAME@::@PROJECT_NAME@")
46
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake")
57

config/template.pc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ Description: @PROJECT_DESCRIPTION@
77
Version: @PROJECT_VERSION@
88
Requires: mctc-lib
99
Libs: -L${libdir} -l@PROJECT_NAME@
10-
Cflags: -I${includedir} -I${includedir}/@PROJECT_NAME@/modfiles
10+
Cflags: -I${includedir} -I${includedir}/@module-dir@

meson.build

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,16 @@ if install
6868
install_dir: get_option('datadir')/'licenses'/meson.project_name()
6969
)
7070

71+
module_id = meson.project_name() / fc_id + '-' + fc.version()
72+
meson.add_install_script(
73+
find_program(files('config'/'install-mod.py')),
74+
get_option('includedir') / module_id,
75+
)
76+
7177
pkg = import('pkgconfig')
7278
pkg.generate(
7379
mstore_lib,
7480
description: 'Molecular structure store for testing',
81+
subdirs: ['', module_id],
7582
)
7683
endif

0 commit comments

Comments
 (0)