59
votes

I'm currently trying to get CMake running for my project (on windows). I want to use a custom location where all libraries are installed. To inform CMake about that path I tried to do that:

set(CMAKE_PREFIX_PATH D:/develop/cmake/libs)

But when I try to find the library with

find_library(CURL_LIBRARY NAMES curl curllib libcurl_imp curllib_static)

CMake can't find it. When I set my prefix path to

set(CMAKE_PREFIX_PATH D:/develop/cmake/libs/curl)

... the library is located.

So my question is: How can I configure CMake properly to work with a directory structore at a custom location which looks like that:

D:/develop/cmake/libs/
-> libA
   -> include
   -> lib
-> libB
   -> include
   -> lib
-> ...
   -> include
   -> lib

In "include" lie the public headers and in "lib" are the compiled libraries.

Hope someone can help me - Thanks in advance

edit: The current workaround for me is, to do this before i search for libraries:

set(CUSTOM_LIBRARY_PATH D:/develop/cmake/libs)
file(GLOB sub-dir ${CUSTOM_LIBRARY_PATH}/*)
foreach(dir ${sub-dir})
    if(IS_DIRECTORY ${dir})
        set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH};${dir})
    endif()
endforeach()

But that way the default module for boost wont find it until it because the directory structore of boost is a bit different.

boost -> include -> boost-1_50 -> *.hpp

When I move the content if "boost-1_50" to "include" the library can be found but that way it's not possible to handle multiple versions right?

6
First, why are you setting CMAKE_PREFIX_PATH inside CMakeLists.txt? This will not work if another guy would try to compile your project.arrowd
It was only for testing - if it would work I would use an environment variableDaniel

6 Answers

32
votes

The simplest solution may be to add HINTS to each find_* request.

For example:

find_library(CURL_LIBRARY
    NAMES curl curllib libcurl_imp curllib_static
    HINTS "${CMAKE_PREFIX_PATH}/curl/lib"
)

For Boost I would strongly recommend using the FindBoost standard module and setting the BOOST_DIR variable to point to your Boost libraries.

18
votes

I saw that two people put that question to their favorites so I will try to answer the solution which works for me: Instead of using find modules I'm writing configuration files for all libraries which are installed. Those files are extremly simple and can also be used to set non-standard variables. CMake will (at least on windows) search for those configuration files in

CMAKE_PREFIX_PATH/<<package_name>>-<<version>>/<<package_name>>-config.cmake

(which can be set through an environment variable). So for example the boost configuration is in the path

CMAKE_PREFIX_PATH/boost-1_50/boost-config.cmake

In that configuration you can set variables. My config file for boost looks like that:

set(boost_INCLUDE_DIRS ${boost_DIR}/include)
set(boost_LIBRARY_DIR ${boost_DIR}/lib)
foreach(component ${boost_FIND_COMPONENTS}) 
    set(boost_LIBRARIES ${boost_LIBRARIES} debug ${boost_LIBRARY_DIR}/libboost_${component}-vc110-mt-gd-1_50.lib)
    set(boost_LIBRARIES ${boost_LIBRARIES} optimized ${boost_LIBRARY_DIR}/libboost_${component}-vc110-mt-1_50.lib)
endforeach()
add_definitions( -D_WIN32_WINNT=0x0501 )

Pretty straight forward + it's possible to shrink the size of the config files even more when you write some helper functions. The only issue I have with this setup is that I havn't found a way to give config files a priority over find modules - so you need to remove the find modules.

Hope this this is helpful for other people.

9
votes

Use CMAKE_PREFIX_PATH by adding multiple paths (separated by semicolons and no white spaces). You can set it as an environmental variable to avoid having absolute paths in your cmake configuration files

Notice that cmake will look for config file in any of the following folders where is any of the path in CMAKE_PREFIX_PATH and name is the name of the library you are looking for

<prefix>/                                               (W)
<prefix>/(cmake|CMake)/                                 (W)
<prefix>/<name>*/                                       (W)
<prefix>/<name>*/(cmake|CMake)/                         (W)
<prefix>/(lib/<arch>|lib|share)/cmake/<name>*/          (U)
<prefix>/(lib/<arch>|lib|share)/<name>*/                (U)
<prefix>/(lib/<arch>|lib|share)/<name>*/(cmake|CMake)/  (U)

In your case you need to add to CMAKE_PREFIX_PATH the following two paths:

D:/develop/cmake/libs/libA;D:/develop/cmake/libB
7
votes

There is no way to automatically set CMAKE_PREFIX_PATH in a way you want. I see following ways to solve this problem:

  1. Put all libraries files in the same dir. That is, include/ would contain headers for all libs, lib/ - binaries, etc. FYI, this is common layout for most UNIX-like systems.

  2. Set global environment variable CMAKE_PREFIX_PATH to D:/develop/cmake/libs/libA;D:/develop/cmake/libs/libB;.... When you run CMake, it would aautomatically pick up this env var and populate it's own CMAKE_PREFIX_PATH.

  3. Write a wrapper .bat script, which would call cmake command with -D CMAKE_PREFIX_PATH=... argument.

7
votes

You have one extra level of nesting. CMAKE will search under $CMAKE_PREFIX_PATH/include for headers and $CMAKE_PREFIX_PATH/libs for libraries.

From CMAKE documentation:

For each path in the CMAKE_PREFIX_PATH list, CMake will check "PATH/include" and "PATH" when FIND_PATH() is called, "PATH/bin" and "PATH" when FIND_PROGRAM() is called, and "PATH/lib and "PATH" when FIND_LIBRARY() is called.

-2
votes

I've encountered a similar scenario. I solved it by adding in this following code just before find_library():

set(CMAKE_PREFIX_PATH /the/custom/path/to/your/lib/)

then it can find the library location.