Skip to content

Commit

Permalink
Add support for FetchContent
Browse files Browse the repository at this point in the history
  • Loading branch information
bansan85 committed Jun 18, 2023
1 parent 377cddc commit 2a295b9
Show file tree
Hide file tree
Showing 10 changed files with 110 additions and 31 deletions.
9 changes: 5 additions & 4 deletions .github/workflows/cmake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ jobs:
build_type: [Debug, Release]
name: [gcc, clang, windows, clang-cfi]
build_shared_libs: [ON, OFF]
fetch_content: [ON, OFF]
include:
- name: gcc
ar: /usr/bin/ar
Expand Down Expand Up @@ -78,7 +79,7 @@ jobs:
- name: cmake lib2
run: |
mkdir build_lib2
cmake -S library2 -B build_lib2 -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -Dlibrary_DIR="${{ github.workspace }}/install_path/lib/cmake/library" -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/install_path" -DCMAKE_CXX_COMPILER="${{ matrix.cxx }}" -DCMAKE_AR="${{ matrix.ar }}" -DCMAKE_RANLIB="${{ matrix.ranlib }}" -DBUILD_SHARED_LIBS:BOOL=${{ matrix.build_shared_libs }} -DCMAKE_CXX_FLAGS="${{ matrix.cxx_flags }}" -DCMAKE_EXE_LINKER_FLAGS="${{ matrix.ld_flags }}" -DCMAKE_CXX_STANDARD=20 || exit 1
cmake -S library2 -B build_lib2 -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -Dlibrary_DIR="${{ github.workspace }}/install_path/lib/cmake/library" -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/install_path" -DCMAKE_CXX_COMPILER="${{ matrix.cxx }}" -DCMAKE_AR="${{ matrix.ar }}" -DCMAKE_RANLIB="${{ matrix.ranlib }}" -DBUILD_SHARED_LIBS:BOOL=${{ matrix.build_shared_libs }} -DCMAKE_CXX_FLAGS="${{ matrix.cxx_flags }}" -DCMAKE_EXE_LINKER_FLAGS="${{ matrix.ld_flags }}" -DCMAKE_CXX_STANDARD=20 -DBUILD_FETCH_CONTENT:BOOL="${{ matrix.fetch_content }}" || exit 1
cmake --build build_lib2/ --target ${{ matrix.buildall }} --config ${{ matrix.build_type }} || exit 1
cmake --build build_lib2/ --target install --config ${{ matrix.build_type }} || exit 1
cd build_lib2 || exit 1
Expand All @@ -93,7 +94,7 @@ jobs:
- name: cmake lib3
run: |
mkdir build_lib3
cmake -S library3 -B build_lib3 -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -Dlibrary_DIR="${{ github.workspace }}/install_path/lib/cmake/library" -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/install_path" -DCMAKE_CXX_COMPILER="${{ matrix.cxx }}" -DCMAKE_AR="${{ matrix.ar }}" -DCMAKE_RANLIB="${{ matrix.ranlib }}" -DBUILD_SHARED_LIBS:BOOL=${{ matrix.build_shared_libs }} -DCMAKE_CXX_FLAGS="${{ matrix.cxx_flags }}" -DCMAKE_EXE_LINKER_FLAGS="${{ matrix.ld_flags }}" -DCMAKE_CXX_STANDARD=20 || exit 1
cmake -S library3 -B build_lib3 -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -Dlibrary_DIR="${{ github.workspace }}/install_path/lib/cmake/library" -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/install_path" -DCMAKE_CXX_COMPILER="${{ matrix.cxx }}" -DCMAKE_AR="${{ matrix.ar }}" -DCMAKE_RANLIB="${{ matrix.ranlib }}" -DBUILD_SHARED_LIBS:BOOL=${{ matrix.build_shared_libs }} -DCMAKE_CXX_FLAGS="${{ matrix.cxx_flags }}" -DCMAKE_EXE_LINKER_FLAGS="${{ matrix.ld_flags }}" -DCMAKE_CXX_STANDARD=20 -DBUILD_FETCH_CONTENT:BOOL="${{ matrix.fetch_content }}" || exit 1
cmake --build build_lib3/ --target ${{ matrix.buildall }} --config ${{ matrix.build_type }} || exit 1
cmake --build build_lib3/ --target install --config ${{ matrix.build_type }} || exit 1
cd build_lib3 || exit 1
Expand All @@ -108,7 +109,7 @@ jobs:
- name: cmake lib4
run: |
mkdir build_lib4
cmake -S library4 -B build_lib4 -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -Dlibrary_DIR="${{ github.workspace }}/install_path/lib/cmake/library" -Dlibrary2_DIR="${{ github.workspace }}/install_path/lib/cmake/library2" -Dlibrary3_DIR="${{ github.workspace }}/install_path/lib/cmake/library3" -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/install_path" -DCMAKE_CXX_COMPILER="${{ matrix.cxx }}" -DCMAKE_AR="${{ matrix.ar }}" -DCMAKE_RANLIB="${{ matrix.ranlib }}" -DBUILD_SHARED_LIBS:BOOL=${{ matrix.build_shared_libs }} -DCMAKE_CXX_FLAGS="${{ matrix.cxx_flags }}" -DCMAKE_EXE_LINKER_FLAGS="${{ matrix.ld_flags }}" -DCMAKE_CXX_STANDARD=20 || exit 1
cmake -S library4 -B build_lib4 -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -Dlibrary_DIR="${{ github.workspace }}/install_path/lib/cmake/library" -Dlibrary2_DIR="${{ github.workspace }}/install_path/lib/cmake/library2" -Dlibrary3_DIR="${{ github.workspace }}/install_path/lib/cmake/library3" -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/install_path" -DCMAKE_CXX_COMPILER="${{ matrix.cxx }}" -DCMAKE_AR="${{ matrix.ar }}" -DCMAKE_RANLIB="${{ matrix.ranlib }}" -DBUILD_SHARED_LIBS:BOOL=${{ matrix.build_shared_libs }} -DCMAKE_CXX_FLAGS="${{ matrix.cxx_flags }}" -DCMAKE_EXE_LINKER_FLAGS="${{ matrix.ld_flags }}" -DCMAKE_CXX_STANDARD=20 -DBUILD_FETCH_CONTENT:BOOL="${{ matrix.fetch_content }}" || exit 1
cmake --build build_lib4/ --target ${{ matrix.buildall }} --config ${{ matrix.build_type }} || exit 1
cmake --build build_lib4/ --target install --config ${{ matrix.build_type }} || exit 1
cd build_lib4 || exit 1
Expand All @@ -123,7 +124,7 @@ jobs:
- name: cmake main
run: |
mkdir main
cmake -S extern -B main -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -Dlibrary_DIR="${{ github.workspace }}/install_path/lib/cmake/library" -Dlibrary2_DIR="${{ github.workspace }}/install_path/lib/cmake/library2" -Dlibrary3_DIR="${{ github.workspace }}/install_path/lib/cmake/library3" -Dlibrary4_DIR="${{ github.workspace }}/install_path/lib/cmake/library4" -DCMAKE_CXX_COMPILER="${{ matrix.cxx }}" -DCMAKE_AR="${{ matrix.ar }}" -DCMAKE_RANLIB="${{ matrix.ranlib }}" -DBUILD_SHARED_LIBS:BOOL=${{ matrix.build_shared_libs }} -DCMAKE_CXX_FLAGS="${{ matrix.cxx_flags }}" -DCMAKE_EXE_LINKER_FLAGS="${{ matrix.ld_flags }}" -DCMAKE_CXX_STANDARD=20 || exit 1
cmake -S extern -B main -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -Dlibrary_DIR="${{ github.workspace }}/install_path/lib/cmake/library" -Dlibrary2_DIR="${{ github.workspace }}/install_path/lib/cmake/library2" -Dlibrary3_DIR="${{ github.workspace }}/install_path/lib/cmake/library3" -Dlibrary4_DIR="${{ github.workspace }}/install_path/lib/cmake/library4" -DCMAKE_CXX_COMPILER="${{ matrix.cxx }}" -DCMAKE_AR="${{ matrix.ar }}" -DCMAKE_RANLIB="${{ matrix.ranlib }}" -DBUILD_SHARED_LIBS:BOOL=${{ matrix.build_shared_libs }} -DCMAKE_CXX_FLAGS="${{ matrix.cxx_flags }}" -DCMAKE_EXE_LINKER_FLAGS="${{ matrix.ld_flags }}" -DCMAKE_CXX_STANDARD=20 -DBUILD_FETCH_CONTENT:BOOL="${{ matrix.fetch_content }}" || exit 1
cmake --build main/ --target ${{ matrix.buildall }} --config ${{ matrix.build_type }} || exit 1
- name: ctest main
shell: bash
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ After, a simple executable `extern` is linked with `library4`.

## CMakeLists.txt

All interesting data in this POC are in `CMakeLists.txt` files in `library` folder. The other folders are just a clone of this folder to show that everything is working well for the worst scenario.
All interesting data in this POC are in `CMakeLists.txt` files in `library` folder. There is also comment about `BUILD_FETCH_CONTENT` in `lib/CmakeLists.txt` for `library2`. The other folders are just a clone of the main folder to show that everything is working well for the worst scenario.

You need to know the basics of CMake. The whole [official tutorial](https://cmake.org/cmake/help/latest/guide/tutorial/index.html) is perfect.

Expand All @@ -43,6 +43,8 @@ Diamond dependency doesn't look to be a problem with this example.

Don't explicitly (on user side) depends on `library` when linking `library2` or `library3`. But you need to explicitly do it in `Config.cmake` file.

Libraries can be built with `FetchContent` or `find_package`. Simply set `BUILD_FETCH_CONTENT` option.

## Fix-me

Don't set `CMAKE_INSTALL_RPATH` and `CMAKE_INSTALL_RPATH_USE_LINK_PATH` in `CMakeLists.txt`. But without it, CI don't pass.
Don't set `CMAKE_INSTALL_RPATH` and `CMAKE_INSTALL_RPATH_USE_LINK_PATH` in `CMakeLists.txt`. But without it, CI doesn't pass.
22 changes: 18 additions & 4 deletions extern/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,25 @@ cmake_minimum_required(VERSION 3.21)
project(Extern)

option(BUILD_SHARED_LIBS "Build using shared libraries" OFF)
option(BUILD_FETCH_CONTENT
"Use FetchContext instead of find_package for external library" OFF)

find_package(library REQUIRED)
find_package(library2 REQUIRED)
find_package(library3 REQUIRED)
find_package(library4 REQUIRED)
if(BUILD_FETCH_CONTENT)
include(FetchContent)
set(BUILD_TESTING_SAVE ${BUILD_TESTING})
set(BUILD_TESTING OFF)
FetchContent_Declare(library4 SOURCE_DIR
"${CMAKE_CURRENT_SOURCE_DIR}/../library4")
FetchContent_GetProperties(library4)
if(NOT library4_POPULATED)
FetchContent_Populate(library4)
add_subdirectory(${library4_SOURCE_DIR} ${library4_BINARY_DIR}
EXCLUDE_FROM_ALL)
endif()
set(BUILD_TESTING ${BUILD_TESTING_SAVE})
else()
find_package(library4 REQUIRED)
endif()

add_executable(test1 main1.cpp)
target_link_libraries(test1 PRIVATE library::library)
Expand Down
13 changes: 8 additions & 5 deletions library/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/${PROJECT_NAME}/version.h.in
${CMAKE_CURRENT_BINARY_DIR}/include/${PROJECT_NAME}/version.h)

add_library(${PROJECT_NAME})
# library will be installed in a namespace library. But if you don't install the
# library (and use it with add_subdirectory / FetchContent), an alias for
# library::library is needed.
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})

include(GenerateExportHeader)

Expand Down Expand Up @@ -46,12 +50,11 @@ target_sources(
# only if you built library with BUILD_SHARED_LIBS and want to use installed
# headers in STATIC library.

# In shared mode, CMake automatically defines ${PROJECT_NAME}_Export in private.
# For shared library, CMake automatically defines ${PROJECT_NAME}_Export in
# private.

#if(NOT BUILD_SHARED_LIBS)
# target_compile_definitions(${PROJECT_NAME}
# PUBLIC ${PROJECT_NAME}_STATIC_DEFINE)
#endif()
# target_compile_definitions(${PROJECT_NAME} PUBLIC
# ${PROJECT_NAME}_STATIC_DEFINE)

# BUILD_INTERFACE will be the include folder when you build the library.

Expand Down
2 changes: 2 additions & 0 deletions library2/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)

option(BUILD_SHARED_LIBS "Build using shared libraries" OFF)
option(BUILD_FETCH_CONTENT
"Use FetchContext instead of find_package for external library" OFF)

include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
Expand Down
27 changes: 26 additions & 1 deletion library2/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/${PROJECT_NAME}/version.h.in
${CMAKE_CURRENT_BINARY_DIR}/include/${PROJECT_NAME}/version.h)

add_library(${PROJECT_NAME})
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})

include(GenerateExportHeader)

Expand All @@ -19,7 +20,31 @@ set(${PROJECT_NAME}_HEADER_AUTO
${CMAKE_CURRENT_BINARY_DIR}/include/${PROJECT_NAME}/subfolder/helper.h
${CMAKE_CURRENT_BINARY_DIR}/include/${PROJECT_NAME}/version.h)

find_package(library REQUIRED)
# Test compilation / build with FetchContent_Declare or find_package
if(BUILD_FETCH_CONTENT)
include(FetchContent)
# There is a target test1 in library and library2. Hack to disable
# BUILD_TESTING only in library.
set(BUILD_TESTING_SAVE ${BUILD_TESTING})
set(BUILD_TESTING OFF)
FetchContent_Declare(library SOURCE_DIR
"${CMAKE_CURRENT_SOURCE_DIR}/../../library")
# Don't use FetchContent_MakeAvailable since it doesn't support
# EXCLUDE_FROM_ALL. If you don't EXCLUDE_FROM_ALL, you will install library
# with library2.
FetchContent_GetProperties(library)
if(NOT library_POPULATED)
FetchContent_Populate(library)
add_subdirectory(${library_SOURCE_DIR} ${library_BINARY_DIR}
EXCLUDE_FROM_ALL)
endif()
set(BUILD_TESTING ${BUILD_TESTING_SAVE})
else()
find_package(library REQUIRED)
endif()
# With FetchContent, library::library is an alias to library.

# With find_package, it's a real namespace::library.
target_link_libraries(${PROJECT_NAME} PUBLIC library::library)

target_sources(
Expand Down
2 changes: 2 additions & 0 deletions library3/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)

option(BUILD_SHARED_LIBS "Build using shared libraries" OFF)
option(BUILD_FETCH_CONTENT
"Use FetchContext instead of find_package for external library" OFF)

include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
Expand Down
18 changes: 17 additions & 1 deletion library3/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/${PROJECT_NAME}/version.h.in
${CMAKE_CURRENT_BINARY_DIR}/include/${PROJECT_NAME}/version.h)

add_library(${PROJECT_NAME})
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})

include(GenerateExportHeader)

Expand All @@ -19,7 +20,22 @@ set(${PROJECT_NAME}_HEADER_AUTO
${CMAKE_CURRENT_BINARY_DIR}/include/${PROJECT_NAME}/subfolder/helper.h
${CMAKE_CURRENT_BINARY_DIR}/include/${PROJECT_NAME}/version.h)

find_package(library REQUIRED)
if(BUILD_FETCH_CONTENT)
include(FetchContent)
set(BUILD_TESTING_SAVE ${BUILD_TESTING})
set(BUILD_TESTING OFF)
FetchContent_Declare(library SOURCE_DIR
"${CMAKE_CURRENT_SOURCE_DIR}/../../library")
FetchContent_GetProperties(library)
if(NOT library_POPULATED)
FetchContent_Populate(library)
add_subdirectory(${library_SOURCE_DIR} ${library_BINARY_DIR}
EXCLUDE_FROM_ALL)
endif()
set(BUILD_TESTING ${BUILD_TESTING_SAVE})
else()
find_package(library REQUIRED)
endif()
target_link_libraries(${PROJECT_NAME} PUBLIC library::library)

target_sources(
Expand Down
14 changes: 2 additions & 12 deletions library4/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
cmake_minimum_required(VERSION 3.23)

# Configuration of the project needs to set VERSION to generate .cmake files and
# to use find_package.
project(
library4
LANGUAGES CXX
Expand All @@ -10,26 +8,20 @@ project(
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)

# You need to explicitly set BUILD_SHARED_LIBS option to enable static / shared
# library. But don't customize variable name.
option(BUILD_SHARED_LIBS "Build using shared libraries" OFF)
option(BUILD_FETCH_CONTENT
"Use FetchContext instead of find_package for external library" OFF)

# Set default library path to install
include(GNUInstallDirs)
# Features to generate .cmake file for find_package.
include(CMakePackageConfigHelpers)

# Configuration of the library
add_subdirectory(lib)

# Enable tests.
include(CTest)
# BUILD_TESTING is defined via include(CTest)
if(BUILD_TESTING)
add_subdirectory(tests)
endif()

# Generate an installer (requires nsis)
include(InstallRequiredSystemLibraries)
include(CPack)
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/../LICENSE")
Expand All @@ -38,12 +30,10 @@ set(CPACK_PACKAGE_VERSION_MINOR "${${PROJECT_NAME}_VERSION_MINOR}")
set(CPACK_PACKAGE_VERSION_PATCH "${${PROJECT_NAME}_VERSION_PATCH}")
set(CPACK_PACKAGE_VERSION_TWEAK "${${PROJECT_NAME}_VERSION_TWEAK}")
set(CPACK_SOURCE_GENERATOR "TGZ")
# It's better that the folder path have the version of the library.
file(
TO_NATIVE_PATH
"${PROJECT_NAME}/${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}"
path_suggested)
# Need to escape backslash for NSIS.
string(REPLACE "\\" "\\\\" path_suggested "${path_suggested}")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "${path_suggested}")
set(CPACK_NSIS_PACKAGE_NAME
Expand Down
28 changes: 26 additions & 2 deletions library4/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/${PROJECT_NAME}/version.h.in
${CMAKE_CURRENT_BINARY_DIR}/include/${PROJECT_NAME}/version.h)

add_library(${PROJECT_NAME})
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})

include(GenerateExportHeader)

Expand All @@ -19,8 +20,31 @@ set(${PROJECT_NAME}_HEADER_AUTO
${CMAKE_CURRENT_BINARY_DIR}/include/${PROJECT_NAME}/subfolder/helper.h
${CMAKE_CURRENT_BINARY_DIR}/include/${PROJECT_NAME}/version.h)

find_package(library2 REQUIRED)
find_package(library3 REQUIRED)
if(BUILD_FETCH_CONTENT)
include(FetchContent)
set(BUILD_TESTING_SAVE ${BUILD_TESTING})
set(BUILD_TESTING OFF)
FetchContent_Declare(library2 SOURCE_DIR
"${CMAKE_CURRENT_SOURCE_DIR}/../../library2")
FetchContent_GetProperties(library2)
if(NOT library2_POPULATED)
FetchContent_Populate(library2)
add_subdirectory(${library2_SOURCE_DIR} ${library2_BINARY_DIR}
EXCLUDE_FROM_ALL)
endif()
FetchContent_Declare(library3 SOURCE_DIR
"${CMAKE_CURRENT_SOURCE_DIR}/../../library3")
FetchContent_GetProperties(library3)
if(NOT library3_POPULATED)
FetchContent_Populate(library3)
add_subdirectory(${library3_SOURCE_DIR} ${library3_BINARY_DIR}
EXCLUDE_FROM_ALL)
endif()
set(BUILD_TESTING ${BUILD_TESTING_SAVE})
else()
find_package(library2 REQUIRED)
find_package(library3 REQUIRED)
endif()
target_link_libraries(${PROJECT_NAME} PUBLIC library2::library2
library3::library3)

Expand Down

0 comments on commit 2a295b9

Please sign in to comment.