PACKAGE_INIT generates PACKAGE_PREFIX_DIR with the wrong directory

I have a very small library called pi-events, and I’m trying to install it locally to another project I have called sdl-sandbox, which lives in D:/projects/sdl-sandbox

My pi-events-config.cmake.in file looks like this:

@PACKAGE_INIT@

include("${CMAKE_CURRENT_LIST_DIR}/pi-events-targets.cmake")
check_required_component(pi-events)

And the generated file that gets installed has this line:

get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/C:/Program Files (x86)/sdl-sandbox" ABSOLUTE)

Obviously this is going to cause some problems, b/c like I said, the sdl-sandbox project lives in D:/projects, not C:/Program Files (x86)

This is how I’ve defined pi-events-targets:

# create and install the target files
install(EXPORT pi-events-targets
        FILE pi-events-targets.cmake
        NAMESPACE pi::
        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/pi/events)

I’m entirely sure if this is the only relevant information, but I wasn’t sure if I should dump the whole CMakeLists.txt file here, so let me know if more info is needed.

Is there anyway I can configure @PACKAGE_INIT@ to use the correct prefix dir?

I am only guessing, but what is the value of ${CMAKE_INSTALL_LIBDIR} (you can print it with message())?

Also, do you have this include before the very first time you use ${CMAKE_INSTALL_LIBDIR}:

include(GNUInstallDirs)

install(
    # ...
)

It’s just lib, and yeah I have include(GNUInstallDirs) before the library code

It might also be that you have not set CMAKE_INSTALL_PREFIX, so it defaults to Program Files.
Actually, that is most definitely the reason, I wasn’t thinking straight at first :slight_smile:

So here’s how you’d configure your project:

$ cd /path/to/project
$ mkdir build && cd $_
$ cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="../install" ..
$ cmake --build . --target install

Then the project will install to ./install/ folder in your project root.

1 Like

I haven’t set CMAKE_INSTALL_PREFIX, but when I install I use the command cmake --install . --prefix ../path/to/project. It installs all my library and target files exactly where I expect, but when I try to use find_package(pi-events REQUIRED) it can’t find it, seemingly because the package config helpers generated a file that uses the wrong prefix

I don’t wanna install to the user package base, because this is a hobby project that changes a lot, and I’d rather just install the library directly to local projects for now.

Though I suppose installing to the user package root would likely make my life easier.

install to local projects

Not sure if I understood, but what I’ve described would install to a “local” specified folder.

Anyway, if CMAKE_INSTALL_PREFIX doesn’t improve the situation, then yes, I would take a look at your CMakeLists.txt.

Like this: cmake --install . --prefix ../path/to/project

Doesn’t cmake --build . --target install install to the user package root if you don’t pass it a --prefix argument?

That’s why I mentioned CMAKE_INSTALL_PREFIX - without it installation prefix will default to Program Files (in case of Windows). Not sure if --prefix plays the same role, I never used it before.

I’m pretty sure it does, like I said, all the library and target files get installed exactly where I expect them to, but the package config file doesn’t set up the local project to be able to find the newly installed library, because the generated file is looking in the wrong place (C:/Program Files (x86) instead of D:/projects). But I’ll try what you’re suggesting in case I’m wrong

This worked for getting the package prefix dir correct, but I’m unfortunately still unable to build my subproject because it can’t find the library package, which means there’s something else wrong

getting the package prefix dir correct

You mean get_filename_component(...) now doesn’t contain Program Files anymore?

still unable to build my subproject

How are you looking for it? And why you called it “subproject”? It seems I misunderstood what you are doing.
My understanding was that you build and install one project and then you find its installed package in another project via find_package() (and setting path to it in CMAKE_PREFIX_PATH).

Maybe subproject was a poor choice of words. You’re correct that I want to be able to find the installed package independently of the original library. I think I had an issue with my prefix path missing a directory, but I’m also running into other issues. I probably got it from here though. If I run into another road block, I’ll probably start a new topic if I can’t find any existing solutions online, since your suggestion fixed the problem I described in the topic name.

Also, thank you for your help! Much appreciated

1 Like

Update: The way I’m currently installing and using the library, I don’t even need to use packages. I can just install it and use

add_library(pi-events STATIC IMPORTED)
set_property(TARGET pi-events PROPERTY
             IMPORTED_LOCATION "lib/pi/events/libpi-events.a")

Without having to change the prefix path

I’m now not entirely sure what the advantage is for setting up your library as a package if you’re not going to install to the user or global package root.

what the advantage is for setting up your library as a package

When a library is (correctly) installed as a (relocatable) package, then those who would like to use it in their project would only need to do the following:

find_package(pi-events CONFIG REQUIRED)
target_link_libraries(${PROJECT_NAME} PRIVATE pi-events) # pi::pi-events or pi::events

…and of course provide the path to that package in CMAKE_PREFIX_PATH on configuration.

That way users don’t need to know whether it is STATIC or SHARED, don’t need to manually set IMPORTED_LOCATION property (which requires them to look up the actual binary file name and its location), don’t need to set include directories for public headers and so on, because the package’s CMake config will do all that (and more) behind the scenes.

In addition, your library might have dependencies, and users will then need to manually add those to their projects as well, while with package’s CMake config that also can be managed “automatically” behind the scenes.

I guess this is what’s tripping me up. Like, I either need to set the specific path to the exported targets with set(CMAKE_PREFIX_PATH ...), or I need to set the specific path to the library files with set_property(... IMPORTED_LOCATION ...). With the former option, you also have to generate and install package target files. I suppose a package is more generalized though and may include additional information than just the path to the library.

@craig.scott Is this related to https://gitlab.kitware.com/cmake/cmake/-/merge_requests/9390 ?

I don’t think so, but it would be easy enough to confirm. Try the project with CMake 3.29.1 and 3.29.2. If the problem only occurs with 3.29.1, then MR 9390 would be the likely culprit. That change was reverted in 3.29.2.