Skip to content

Commit 36efd07

Browse files
authored
Support a two-stage build for separate libimas-core / imas-core packaging (#62)
1 parent 5cba5a9 commit 36efd07

5 files changed

Lines changed: 109 additions & 15 deletions

File tree

CMakeLists.txt

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ endif()
3535
# ##############################################################################
3636
option(AL_PYTHON_BINDINGS "Build Python bindings" OFF)
3737

38+
# When ON, the al C++ library is not built here; instead it is located with
39+
# find_package(al-core CONFIG). Enables a two-stage build where libimas-core
40+
# (the C/C++ library) and imas-core (the Python wrapper) are packaged
41+
# separately, e.g. as two conda packages.
42+
option(AL_USE_INSTALLED_CORE
43+
"Link Python bindings against a pre-installed al-core (find_package)" OFF)
44+
3845

3946
# Configuration options for shared libraries
4047
# ##############################################################################
@@ -127,8 +134,31 @@ if(WIN32)
127134
find_package(dlfcn-win32 CONFIG REQUIRED)
128135
endif()
129136

130-
# build AL_CORE library only if backend is enabled
131-
if(AL_BACKEND_HDF5 OR AL_BACKEND_MDSPLUS OR AL_BACKEND_UDA OR AL_BACKEND_UDAFAT OR AL_PYTHON_BINDINGS)
137+
# Two-stage build entry: locate a pre-installed al-core instead of building it.
138+
# Exposes target `al-core::al` and an unqualified alias `al` so the python/
139+
# subdirectory and any consumers can link to `al` transparently.
140+
if(AL_USE_INSTALLED_CORE)
141+
find_package(al-core CONFIG)
142+
if(NOT al-core_FOUND)
143+
message(FATAL_ERROR
144+
"AL_USE_INSTALLED_CORE=ON requires an installed al-core that ships "
145+
"al-coreConfig.cmake (introduced in IMAS-Core 5.7.1 or later). "
146+
"find_package(al-core CONFIG) could not locate it.\n"
147+
"Point CMAKE_PREFIX_PATH (or al-core_DIR) at an install prefix that "
148+
"contains lib/cmake/al-core/al-coreConfig.cmake — typically the "
149+
"stage-1 install tree of this branch. Releases built before this "
150+
"change (e.g. IMAS-Core/5.6.0) only ship al-core.pc and will NOT "
151+
"satisfy AL_USE_INSTALLED_CORE; either install stage 1 from source "
152+
"or wait for a release that includes the CMake package config.")
153+
endif()
154+
if(NOT TARGET al)
155+
add_library(al ALIAS al-core::al)
156+
endif()
157+
endif()
158+
159+
# build AL_CORE library only if backend is enabled and we are not reusing an
160+
# already-installed al-core
161+
if((AL_BACKEND_HDF5 OR AL_BACKEND_MDSPLUS OR AL_BACKEND_UDA OR AL_BACKEND_UDAFAT OR AL_PYTHON_BINDINGS) AND NOT AL_USE_INSTALLED_CORE)
132162

133163
# Core dependencies
134164
set(Boost_USE_MULTITHREADED FALSE)
@@ -199,14 +229,43 @@ add_dependencies( imas_print_version al )
199229
# ##############################################################################
200230

201231
# Install al library
232+
include(GNUInstallDirs)
202233
install(
203234
TARGETS al
235+
EXPORT al-coreTargets
204236
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
205237
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
206238
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
207239
COMPONENT core
208240
)
209241

242+
# Export CMake package config so downstream projects (notably the Python
243+
# wrapper built with AL_USE_INSTALLED_CORE=ON) can `find_package(al-core CONFIG)`.
244+
include(CMakePackageConfigHelpers)
245+
set(_al_core_cmake_dir ${CMAKE_INSTALL_LIBDIR}/cmake/al-core)
246+
install(
247+
EXPORT al-coreTargets
248+
FILE al-coreTargets.cmake
249+
NAMESPACE al-core::
250+
DESTINATION ${_al_core_cmake_dir}
251+
)
252+
configure_package_config_file(
253+
${CMAKE_CURRENT_SOURCE_DIR}/cmake/al-coreConfig.cmake.in
254+
${CMAKE_CURRENT_BINARY_DIR}/al-coreConfig.cmake
255+
INSTALL_DESTINATION ${_al_core_cmake_dir}
256+
)
257+
write_basic_package_version_file(
258+
${CMAKE_CURRENT_BINARY_DIR}/al-coreConfigVersion.cmake
259+
VERSION ${PROJECT_VERSION}
260+
COMPATIBILITY SameMajorVersion
261+
)
262+
install(
263+
FILES
264+
${CMAKE_CURRENT_BINARY_DIR}/al-coreConfig.cmake
265+
${CMAKE_CURRENT_BINARY_DIR}/al-coreConfigVersion.cmake
266+
DESTINATION ${_al_core_cmake_dir}
267+
)
268+
210269
# TODO: put public heades in a separate directory?
211270
install(
212271
FILES ${PUBLIC_HEADER_FILES}
@@ -240,14 +299,15 @@ install(DIRECTORY common TYPE DATA)
240299
# Install Dummy
241300
install(TARGETS imas_print_version DESTINATION bin)
242301

243-
# Scikit-build-core entry point for python bindings
302+
endif() # AL core library: (AL_BACKEND_* OR AL_PYTHON_BINDINGS) AND NOT AL_USE_INSTALLED_CORE
303+
304+
# Scikit-build-core entry point for python bindings — works whether `al` was
305+
# just built here or imported via find_package(al-core).
244306
# ##############################################################################
245307
if(AL_PYTHON_BINDINGS)
246308
include(skbuild.cmake)
247309
endif()
248310

249-
endif() # AL core library (AL_BACKEND_HDF5 OR AL_BACKEND_MDSPLUS OR AL_BACKEND_UDA OR AL_BACKEND_UDAFAT OR AL_PYTHON_BINDINGS)
250-
251311

252312
# MDSplus models
253313
# ##############################################################################

cmake/al-coreConfig.cmake.in

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@PACKAGE_INIT@
2+
3+
include(CMakeFindDependencyMacro)
4+
find_dependency(Boost COMPONENTS filesystem)
5+
6+
include("${CMAKE_CURRENT_LIST_DIR}/al-coreTargets.cmake")
7+
8+
check_required_components(al-core)

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ AL_BACKEND_UDA = { env = "AL_BACKEND_UDA", default = "ON" }
8383
AL_BACKEND_MDSPLUS = { env = "AL_BACKEND_MDSPLUS", default = "OFF" }
8484
AL_BUILD_MDSPLUS_MODELS = { env = "AL_BUILD_MDSPLUS_MODELS", default = "OFF" }
8585
AL_PYTHON_BINDINGS = "ON"
86+
AL_USE_INSTALLED_CORE = { env = "AL_USE_INSTALLED_CORE", default = "OFF" }
8687
DOWNLOAD_DEPENDENCIES = { env = "DOWNLOAD_DEPENDENCIES", default = "ON" }
8788
DD_GIT_REPOSITORY = { env = "DD_GIT_REPOSITORY", default = "EMPTY" }
8889
DD_VERSION = { env = "DD_VERSION", default = "EMPTY" }

python/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@ python_add_library(al_defs MODULE ${al_defs_source} WITH_SOABI)
88
target_link_libraries(_al_lowlevel PRIVATE Python::NumPy al)
99
target_link_libraries(al_defs PRIVATE Python::NumPy al)
1010

11+
if(AL_USE_INSTALLED_CORE)
12+
# libal is provided externally (e.g. the libimas-core conda package).
13+
# Install only the Python extensions — the dynamic linker resolves libal
14+
# at load time via the host's normal library search path / rpath.
15+
install(TARGETS _al_lowlevel al_defs DESTINATION imas_core)
16+
return()
17+
endif()
18+
1119
# Handling RPATH in macOS:
1220
if(APPLE)
1321
set_target_properties(al PROPERTIES INSTALL_RPATH "@loader_path")

skbuild.cmake

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,36 @@ elseif(NOT ${AL_PYTHON_BINDINGS} MATCHES "[Oo][Nn]")
3434
message(FATAL_ERROR "AL_PYTHON_BINDINGS=${AL_PYTHON_BINDINGS} not e|editable|no-build-isolation|[Oo][Nn]")
3535
endif()
3636

37-
add_custom_command(
38-
TARGET al POST_BUILD
39-
COMMAND
40-
${CMAKE_COMMAND} -E env
37+
if(AL_USE_INSTALLED_CORE)
38+
# `al` is an ALIAS to an imported target — it is not built in this tree,
39+
# so it cannot carry a POST_BUILD hook. Drive pip wheel from the custom
40+
# target itself, and put it in ALL so `cmake --build` triggers it.
41+
add_custom_target(al-python-bindings ALL
42+
COMMAND
43+
${CMAKE_COMMAND} -E env
4144
CMAKE_ARGS=${CMAKE_ARGS}
42-
SKBUILD_BUILD_DIR=${CMAKE_CURRENT_BINARY_DIR}/{wheel_tag}
45+
SKBUILD_BUILD_DIR=${CMAKE_CURRENT_BINARY_DIR}/{wheel_tag}
4346
${Python_EXECUTABLE}
44-
-m pip wheel
47+
-m pip wheel
4548
${CMAKE_CURRENT_SOURCE_DIR}
46-
${PIP_OPTIONS}
47-
--wheel-dir ${CMAKE_CURRENT_BINARY_DIR}/dist/
48-
)
49-
add_custom_target(al-python-bindings DEPENDS al)
49+
${PIP_OPTIONS}
50+
--wheel-dir ${CMAKE_CURRENT_BINARY_DIR}/dist/
51+
)
52+
else()
53+
add_custom_command(
54+
TARGET al POST_BUILD
55+
COMMAND
56+
${CMAKE_COMMAND} -E env
57+
CMAKE_ARGS=${CMAKE_ARGS}
58+
SKBUILD_BUILD_DIR=${CMAKE_CURRENT_BINARY_DIR}/{wheel_tag}
59+
${Python_EXECUTABLE}
60+
-m pip wheel
61+
${CMAKE_CURRENT_SOURCE_DIR}
62+
${PIP_OPTIONS}
63+
--wheel-dir ${CMAKE_CURRENT_BINARY_DIR}/dist/
64+
)
65+
add_custom_target(al-python-bindings DEPENDS al)
66+
endif()
5067
set_target_properties(
5168
al-python-bindings PROPERTIES DIST_FOLDER ${CMAKE_CURRENT_BINARY_DIR}/dist/)
5269
install(CODE "execute_process(COMMAND ${Python_EXECUTABLE}

0 commit comments

Comments
 (0)