Skip to content

Remove export(PACKAGE <PackageName>) from CMakeLists #114

@QuaternionsRock

Description

@QuaternionsRock

The export(PACKAGE <PackageName>) command causes a whole host of problems, and it does nothing by default as of CMake 3.15. Given the dubious utility of the user package registry in general (I have yet to find another instance of a major CMake project that populates it), I recommend that all instances of the command be either removed or gated behind an opt-in flag.

My primary motivation is that it creates problems when SystemC is made available through FetchContent. For example, the following CMakeLists file pulls SystemC 3.0.1 from this repository and builds it from source:

cmake_minimum_required(VERSION 3.28.0)
project(my_systemc_test VERSION 0.1.0 LANGUAGES C CXX)

include(FetchContent)

FetchContent_Declare(
    SystemCLanguage
    GIT_REPOSITORY https://github.com/accellera-official/systemc.git
    GIT_TAG 3.0.1
)
FetchContent_MakeAvailable(SystemCLanguage)

add_executable(my_systemc_test main.cpp)
target_link_libraries(my_systemc_test PRIVATE SystemC::systemc)

Even though this project requires CMake 3.28.0, SystemC itself only requires CMake 3.5, meaning CMP0090 is not in effect when SystemC is being built. As a result, unless set(CMAKE_EXPORT_NO_PACKAGE_REGISTRY ON) is called somewhere before the FetchContent_MakeAvailable(SystemCLanguage) call, the user package registry is populated with links to build/_deps/systemclanguage-build/. This is obviously problematic, as it will cause other (unrelated) projects to find this project's copy of SystemC when calling find_package(SystemCLanguage). Furthermore, use of this project's copy will fail with the following error because it was never actually installed:

CMake Error at ~/my_systemc_test/build/_deps/systemc-build/SystemCLanguageConfig.cmake:44 (include):
  include could not find requested file:

    ~/my_systemc_test/build/_deps/systemc-build/SystemCLanguageTargets.cmake

Lastly, FetchContent also includes a neat little feature where it will first attempt to find the package with find_package, downloading and building the package from source only if find_package fails. This can be done like so:

FetchContent_Declare(
    SystemCLanguage
    GIT_REPOSITORY https://github.com/accellera-official/systemc.git
    GIT_TAG 3.0.1
    FIND_PACKAGE_ARGS
)

You can even use this to download and build the package from source if find_package cannot find the requested version:

FetchContent_Declare(
    SystemCLanguage
    GIT_REPOSITORY https://github.com/accellera-official/systemc.git
    GIT_TAG 3.0.1
    FIND_PACKAGE_ARGS 3.0.1
)

Beautiful, isn't it? However, this results in the hardest-to-diagnose behavior of them all:

  • When SystemC is already installed on the system, it finds the package correctly every time.
  • Otherwise, it correctly downloads and builds SystemC from source the first time the project is configured. However, this also adds this project's copy of SystemC to the user package registry, meaning find_package will "succeed" during subsequent configures, and then the configure will fail with the above error, once again because it was never actually installed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions