23

I have a problem with cmake. I have, lets say, CMakeLists1 which has a subdirectory where CMakeLists2 is.

In CMakeLists2 my target is a static library. And I want to link it to external library. I've made it just like that:

link_directories ("path_to_library")
add_library (project2 ${sources})
target_link_libraries (project2 "name_of_external_lib")

Then, I want to use a class from this project2 in my project1. I've made it that way:

add_executable (project1 ${sources})
target_link_libraries (project1 project2)

But that doesn't work at all. First of all, project2 didn't link to external library. Just for checking, I've added this library through vs10 project properties, and the sizes were different. And the second thing, somehow project1 sees that external library (it is in library dependencies of this project) and of course can't find it.

What is the problem?

Ov3r1oad
  • 897
  • 1
  • 9
  • 24
  • 1
    This looks like a duplicate to http://stackoverflow.com/questions/14199708/cmake-include-library-dependencies-in-static-lib Check my answer on that one. – tpg2114 Jan 22 '13 at 22:16
  • Hm, it's actually kind of similar to my problem. But how can I use this command if one lib is external and isn't a target? – Ov3r1oad Jan 22 '13 at 22:54
  • is the 'name_of_external_lib' a shared lib or a static lib ? – matiu Jan 23 '13 at 01:37
  • @Ov3r1oad You would just substitute in the name of the library for the `$` bit. Ideally you are using `find_library` to locate the library and store the name in a variable. That variable would go in place of the second `$` thing. – tpg2114 Jan 23 '13 at 04:24

2 Answers2

11

I think it's CMake's default behavior to not link project2 to the external library, but to link both libraries to the executable. From the book "Mastering CMake".

Since static libraries do not link to the libraries on which they depend, it is important for CMake to keep track of the libraries so they can be specified on the link line of the executable being created.

You could try to use an absolute path in your CMakeLists2:

add_library (project2 ${sources})
target_link_libraries (project2 "path to ext lib"/"name of ext lib")

or you could add

link_directories ("path_to_library")

to the CMakeLists file of project1.

If you really want to do something like in Visual Studio, you could probably use the command given in this answer to build a custom_command in CMake. It probably would look something like this (I didn't test it).

set(EXT_LIB "path_to_library/name_of_external_lib") 
set(BIG_LIB "path_to_big_lib/name_of_big_lib")
add_library (project2 ${sources})
get_property(PROJ2_LOC TARGET project2 PROPERTY LOCATION)

add_custom_command(OUTPUT ${BIG_LIB} 
                   DEPENDS ${EXT_LIB} project2
                   COMMAND "lib.exe /OUT:${BIG_LIB} ${EXT_LIB} ${PROJ2_LOC} )

Then you could link your executable with ${BIG_LIB}.

Some things you have to consider:

  • Maybe you have to use LOCATION_CONFIG (CMake docs, I found the get_property command in this answer )
  • link.exe has to be in your path
  • watch the scope of the BIG_LIB variable if you want to use it in an other CMakeLists.txt
the_storyteller
  • 1,913
  • 20
  • 30
guini
  • 642
  • 1
  • 7
  • 18
  • 1
    Apparently, these are the only options. I just don't understand, why can I implement it in VS10 using "additional library dependencies"? And there is no way to do it in cmake. – Ov3r1oad Jan 24 '13 at 14:15
  • If you uses `SHARED` to build shared libraries and then `target_link_libraries` could link them to external libs. @Ov3r1oad – Lw Cui Dec 17 '16 at 04:43
4

I'm guessing the trouble will likely be that *name_of_external_lib* is not correct so it can't find it.

I would go with:

find_library(
    LIB_I_NEED name_of_external_lib
    HINTS "path_to_library"
)

if(${LIB_I_NEED} STREQUAL "LIB_I_NEED-NOTFOUND")
    message(FATAL_ERROR "Couldn't find the 'external_lib' library)
endif()

message(STATUS "Found 'external_lib' at: ${LIB_I_NEED}")

add_library (project2 ${sources})
target_link_libraries (project2 ${LIB_I_NEED})

If that doesn't help, have a quick read of the example in the cmake docs:

http://www.cmake.org/cmake/help/v2.8.8/cmake.html#command:target_link_libraries

One thing it mentions in there is:

While one repetition is usually sufficient, pathological object file and symbol arrangements can require more. One may handle such cases by manually repeating the component in the last target_link_libraries call

So I would say the other thing to try might be in project2:

set(PROJECT_2_LIBS project2 "name_of_external_lib" PARENT_SCOPE)

then in the exe:

target_link_libraries (project1 ${PROJECT_2_LIBS})

That will have the 'external_lib' linkage repeated in the two places and give you more chance of it working ;)

matiu
  • 6,454
  • 3
  • 40
  • 46
  • Although, I'm thinking now if it's not found, then the compiler would probably complain at some point eh... hmm... - anyway hopefully the answer helps somewhat. – matiu Jan 22 '13 at 22:38
  • Yes, cmake finds this lib, but unfortunately the problem stays. – Ov3r1oad Jan 22 '13 at 22:55