Skip to content

Commit 5f43a3b

Browse files
authored
build(cmake): Add support for building library targets that contain source files and linked libraries. (#36)
1 parent d1b4ae0 commit 5f43a3b

File tree

4 files changed

+87
-22
lines changed

4 files changed

+87
-22
lines changed

CMake/ystdlib-cpp-helpers.cmake

+74-20
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
# @param SOURCE_LIST The list of source files to check.
2+
# @param IS_HEADER_ONLY Returns whether the list only contains header files.
3+
# @param NON_HEADER_FILE Returns the name of the first, if any, non-header file.
4+
function(check_if_header_only SOURCE_LIST IS_HEADER_ONLY NON_HEADER_FILE)
5+
set(_LOCAL_SOURCE_LIST "${${SOURCE_LIST}}")
6+
foreach(src_file IN LISTS _LOCAL_SOURCE_LIST)
7+
if(NOT ${src_file} MATCHES ".*\\.(h|hpp)")
8+
set(${IS_HEADER_ONLY} FALSE PARENT_SCOPE)
9+
set(${NON_HEADER_FILE} ${src_file} PARENT_SCOPE)
10+
return()
11+
endif()
12+
endforeach()
13+
set(${IS_HEADER_ONLY} TRUE PARENT_SCOPE)
14+
set(${NON_HEADER_FILE} "" PARENT_SCOPE)
15+
endfunction()
16+
117
# Adds a c++20 interface library in the subdirectory NAME with the target NAME and alias
218
# NAMESPACE::NAME. Libraries with multiple levels of namespace nesting are currently not supported.
319
#
@@ -6,40 +22,82 @@
622
#
723
# @param NAME
824
# @param NAMESPACE
25+
# @param PUBLIC_HEADERS
26+
# @param PRIVATE_SOURCES
27+
# @param PUBLIC_LINK_LIBRARIES
28+
# @param PRIVATE_LINK_LIBRARIES
929
# @parms TESTS_SOURCES
10-
# @param [LIB_BUILD_INTERFACE="${PROJECT_SOURCE_DIR}/src"] The list of include paths for building
11-
# the library and for external projects that link against it via the add_subdirectory() function.
30+
# @param [BUILD_INCLUDE_DIR="${PROJECT_SOURCE_DIR}/src"] The list of include paths for building the
31+
# library and for external projects that builds `ystdlib-cpp` as a CMAKE subproject via the
32+
# add_subdirectory() function.
1233
function(cpp_library)
1334
set(options "")
1435
set(oneValueArgs
1536
NAME
1637
NAMESPACE
1738
)
1839
set(multiValueArgs
40+
PUBLIC_HEADERS
41+
PRIVATE_SOURCES
42+
PUBLIC_LINK_LIBRARIES
43+
PRIVATE_LINK_LIBRARIES
1944
TESTS_SOURCES
20-
LIB_BUILD_INTERFACE
45+
BUILD_INCLUDE_DIR
2146
)
2247
cmake_parse_arguments(arg_cpp_lib "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
2348

49+
set(_ALIAS_TARGET_NAME "${arg_cpp_lib_NAMESPACE}::${arg_cpp_lib_NAME}")
50+
2451
# TODO: Turn this into a function for handling other optional params that have default values.
25-
if("LIB_BUILD_INTERFACE" IN_LIST arg_cpp_lib_KEYWORDS_MISSING_VALUES)
52+
if("BUILD_INCLUDE_DIR" IN_LIST arg_cpp_lib_KEYWORDS_MISSING_VALUES)
53+
message(FATAL_ERROR "Missing build interface list for ${_ALIAS_TARGET_NAME}.")
54+
elseif(NOT DEFINED arg_cpp_lib_BUILD_INCLUDE_DIR)
55+
set(arg_cpp_lib_BUILD_INCLUDE_DIR "${PROJECT_SOURCE_DIR}/src")
56+
endif()
57+
58+
check_if_header_only(arg_cpp_lib_PUBLIC_HEADERS _IS_VALID_INTERFACE _INVALID_HEADER_FILE)
59+
if(NOT _IS_VALID_INTERFACE)
2660
message(
2761
FATAL_ERROR
28-
"Missing build interface list for ${arg_cpp_lib_NAMESPACE}::${arg_cpp_lib_NAME}."
62+
"Invalid interface header file ${_INVALID_HEADER_FILE} for ${_ALIAS_TARGET_NAME}."
63+
)
64+
endif()
65+
66+
check_if_header_only(arg_cpp_lib_PRIVATE_SOURCES _IS_INTERFACE_LIB _)
67+
if(_IS_INTERFACE_LIB)
68+
add_library(${arg_cpp_lib_NAME} INTERFACE)
69+
target_include_directories(
70+
${arg_cpp_lib_NAME}
71+
INTERFACE
72+
"$<BUILD_INTERFACE:${arg_cpp_lib_BUILD_INCLUDE_DIR}>"
73+
)
74+
target_compile_features(${arg_cpp_lib_NAME} INTERFACE cxx_std_20)
75+
else()
76+
# The library type is specified by `BUILD_SHARED_LIBS` if it is defined. Otherwise, the type
77+
# defaults to static.
78+
add_library(${arg_cpp_lib_NAME})
79+
target_sources(
80+
${arg_cpp_lib_NAME}
81+
PRIVATE
82+
${arg_cpp_lib_PUBLIC_HEADERS}
83+
${arg_cpp_lib_PRIVATE_SOURCES}
84+
)
85+
target_include_directories(
86+
${arg_cpp_lib_NAME}
87+
PUBLIC
88+
"$<BUILD_INTERFACE:${arg_cpp_lib_BUILD_INCLUDE_DIR}>"
2989
)
30-
elseif(NOT DEFINED arg_cpp_lib_LIB_BUILD_INTERFACE)
31-
set(arg_cpp_lib_LIB_BUILD_INTERFACE "${PROJECT_SOURCE_DIR}/src")
90+
target_compile_features(${arg_cpp_lib_NAME} PUBLIC cxx_std_20)
3291
endif()
3392

34-
# Build interface library
35-
add_library(${arg_cpp_lib_NAME} INTERFACE)
36-
target_include_directories(
93+
target_link_libraries(
3794
${arg_cpp_lib_NAME}
38-
INTERFACE
39-
"$<BUILD_INTERFACE:${arg_cpp_lib_LIB_BUILD_INTERFACE}>"
95+
PUBLIC
96+
${arg_cpp_lib_PUBLIC_LINK_LIBRARIES}
97+
PRIVATE
98+
${arg_cpp_lib_PRIVATE_LINK_LIBRARIES}
4099
)
41-
target_compile_features(${arg_cpp_lib_NAME} INTERFACE cxx_std_20)
42-
add_library(${arg_cpp_lib_NAMESPACE}::${arg_cpp_lib_NAME} ALIAS ${arg_cpp_lib_NAME})
100+
add_library(${_ALIAS_TARGET_NAME} ALIAS ${arg_cpp_lib_NAME})
43101

44102
if(YSTDLIB_CPP_ENABLE_TESTS)
45103
# Build library-specific unit test target
@@ -50,7 +108,7 @@ function(cpp_library)
50108
${_UNIT_TEST_TARGET}
51109
PRIVATE
52110
Catch2::Catch2WithMain
53-
${arg_cpp_lib_NAMESPACE}::${arg_cpp_lib_NAME}
111+
${_ALIAS_TARGET_NAME}
54112
)
55113
target_compile_features(${_UNIT_TEST_TARGET} PRIVATE cxx_std_20)
56114
set_property(
@@ -63,10 +121,6 @@ function(cpp_library)
63121

64122
# Link against unified unit test
65123
target_sources(${UNIFIED_UNIT_TEST_TARGET} PRIVATE ${arg_cpp_lib_TESTS_SOURCES})
66-
target_link_libraries(
67-
${UNIFIED_UNIT_TEST_TARGET}
68-
PRIVATE
69-
${arg_cpp_lib_NAMESPACE}::${arg_cpp_lib_NAME}
70-
)
124+
target_link_libraries(${UNIFIED_UNIT_TEST_TARGET} PRIVATE ${_ALIAS_TARGET_NAME})
71125
endif()
72126
endfunction()

CMakeLists.txt

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ project(YSTDLIB_CPP LANGUAGES CXX)
44

55
set(YSTDLIB_CPP_VERSION "0.0.1" CACHE STRING "Project version.")
66

7+
option(BUILD_SHARED_LIBS "Build using shared libraries." OFF)
8+
option(YSTDLIB_CPP_BUILD_TESTING "Build the testing tree for ystdlib-cpp." ON)
9+
710
# Require compiler versions that support the C++20 features necessary for compiling ystdlib-cpp
811
if("AppleClang" STREQUAL "${CMAKE_CXX_COMPILER_ID}")
912
set(YSTDLIB_CPP_CMAKE_CXX_COMPILER_MIN_VERSION "16")
@@ -43,7 +46,6 @@ if(YSTDLIB_CPP_IS_TOP_LEVEL)
4346
include(CTest)
4447
endif()
4548

46-
option(YSTDLIB_CPP_BUILD_TESTING "Build the testing tree for ystdlib-cpp." ON)
4749
if(BUILD_TESTING AND YSTDLIB_CPP_BUILD_TESTING)
4850
set(YSTDLIB_CPP_ENABLE_TESTS ON)
4951
endif()

src/ystdlib/containers/CMakeLists.txt

+8-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,8 @@
1-
cpp_library(NAME container NAMESPACE ystdlib TESTS_SOURCES test/test_Array.cpp)
1+
cpp_library(
2+
NAME containers
3+
NAMESPACE ystdlib
4+
PUBLIC_HEADERS
5+
Array.hpp
6+
TESTS_SOURCES
7+
test/test_Array.cpp
8+
)

src/ystdlib/error_handling/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
cpp_library(
22
NAME error_handling
33
NAMESPACE ystdlib
4+
PUBLIC_HEADERS
5+
ErrorCode.hpp
46
TESTS_SOURCES
57
test/constants.hpp
68
test/test_ErrorCode.cpp

0 commit comments

Comments
 (0)