123

I have 2 folders "inc" and "lib" in my project which have headers and static libs respectively. How do I tell cmake to use those 2 directories for include and linking respectively?

grasevski
  • 2,894
  • 2
  • 21
  • 22

3 Answers3

181

The simplest way of doing this would be to add

include_directories(${CMAKE_SOURCE_DIR}/inc)
link_directories(${CMAKE_SOURCE_DIR}/lib)

add_executable(foo ${FOO_SRCS})
target_link_libraries(foo bar) # libbar.so is found in ${CMAKE_SOURCE_DIR}/lib

The modern CMake version that doesn't add the -I and -L flags to every compiler invocation would be to use imported libraries:

add_library(bar SHARED IMPORTED) # or STATIC instead of SHARED
set_target_properties(bar PROPERTIES
  IMPORTED_LOCATION "${CMAKE_SOURCE_DIR}/lib/libbar.so"
  INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/include/libbar"
)

set(FOO_SRCS "foo.cpp")
add_executable(foo ${FOO_SRCS})
target_link_libraries(foo bar) # also adds the required include path

If setting the INTERFACE_INCLUDE_DIRECTORIES doesn't add the path, older versions of CMake also allow you to use target_include_directories(bar PUBLIC /path/to/include). However, this no longer works with CMake 3.6 or newer.

ar31
  • 3,576
  • 1
  • 25
  • 22
  • Got this error with CMake 3.6: CMake Error at ...snip.../CMakeLists.txt:8 (target_include_directories): Cannot specify include directories for imported target "myBar". – nodakai Mar 19 '17 at 21:36
  • 1
    Indeed, I have updated my answer and it now works for me with CMake 3.8 – ar31 Mar 29 '17 at 10:44
  • 7
    `link_directories()`, is exactly what looking for. – parasrish Nov 10 '17 at 10:43
  • 9
    While that will work for simple projects it can easily break for more complex build systems and therefore is no longer the recommended way to add linker directories. The problem is that link_directories() will add the `-L` flag to everything in the current directory but it won't be added for other targets that link against a library built in this directory. – ar31 Nov 15 '17 at 22:42
  • 2
    This doesnt work anymore with 3.10.2 version. No -L dir is added when using 'link_directories' and there seems to be no target property – Lothar Jun 12 '18 at 01:44
  • cmake is just too smart for me. It did not add the -L option because this was specified in the environment variable. Smart but not good. If i move the CMake around or call it later the environment may have changed and then you run into trouble. – Lothar Jun 12 '18 at 02:45
  • @ar31 I think the above method is more simple than the below method(IMPORTED),can you point the below method advantage? – Jayhello Jul 13 '18 at 09:00
  • The first method works fine for simple projects, but if you have many subdirectories it is probably better to create your IMPORTED library in one folder and just have all others use `target_link_libraries(foo bar)`. The advantage here is that if any of the flags (such as includes/defines/dependent libraries) change you only need to adjust one location rather than update all CMakeLists.txt – ar31 Jul 16 '18 at 16:00
  • @ar31, Can I be implicit on the library name (For instance in Windows I don't want it to add prefix)? I just want to give it the exact file name to link against. – Royi Sep 19 '18 at 13:58
  • CMAKE changes a lot from versions to versions. Please mark your version when you say something is working. Thanks. – Robin Hsu Sep 25 '18 at 08:18
  • I had a similar issue. Adding the alternative lib folder to CmakeLists.txt, just after setting the CMAKE_CXX_STANDARD, using link_directories("/path/to/lib") , fixed my compilation, it works like a charm. – Fabiano Tarlao Jan 28 '19 at 19:04
  • 1
    Thanks for offering 2 solutions. Both works for me. I am curious why the latter form is introduced/needed/preferred if former is working. Thanks! – HCSF Feb 21 '19 at 07:55
  • where should I put `link_directories()` in the Makefile,.cpp or .hpp ? – Dhiren Hamal Sep 24 '19 at 12:05
  • @DhirenHamal: In CMakeLists.txt – Johann Gerell Feb 25 '22 at 18:06
  • @ar31 I am new to cmake, what is foo and what is bar here? I am on windows and I want to link this library C:/Program Files/IBM/ILOG/CPLEX_Studio1210/cplex/lib/x64_windows_msvc14/stat_mda/cplex12100.lib, what should be foo in this case? – sos Oct 06 '22 at 06:29
10

might fail working with link_directories, then add each static library like following:

target_link_libraries(foo /path_to_static_library/libbar.a)
Oleg Kokorin
  • 2,288
  • 2
  • 16
  • 28
10

You had better use find_library command instead of link_directories. Concretely speaking there are two ways:

  1. designate the path within the command

    find_library(NAMES gtest PATHS path1 path2 ... pathN)

  2. set the variable CMAKE_LIBRARY_PATH

    set(CMAKE_LIBRARY_PATH path1 path2)
    find_library(NAMES gtest)

the reason is as flowings:

Note This command is rarely necessary and should be avoided where there are other choices. Prefer to pass full absolute paths to libraries where possible, since this ensures the correct library will always be linked. The find_library() command provides the full path, which can generally be used directly in calls to target_link_libraries(). Situations where a library search path may be needed include: Project generators like Xcode where the user can switch target architecture at build time, but a full path to a library cannot be used because it only provides one architecture (i.e. it is not a universal binary).

Libraries may themselves have other private library dependencies that expect to be found via RPATH mechanisms, but some linkers are not able to fully decode those paths (e.g. due to the presence of things like $ORIGIN).

If a library search path must be provided, prefer to localize the effect where possible by using the target_link_directories() command rather than link_directories(). The target-specific command can also control how the search directories propagate to other dependent targets.

Lincoln Yesire
  • 159
  • 1
  • 4