Vincent
Vincent

Reputation: 60341

CMake : how to link a library WITHOUT automatic search function FIND_PACKAGE?

I wonder how to find/link a library without any FIND_PACKAGE.

Assume that we have a "personal" library called testlib :

/perso/testlib/include/testlib1.h
/perso/testlib/include/testlib2.h
/perso/testlib/lib/testlib1.a
/perso/testlib/lib/testlib2.a

How to link it with CMake ?

1) What are the functions to link it directly in the code of the CMakeLists.txt ?

2) How to allow the user to select where are the files ?

3) I have difficulties to understand what is interpreted and what it's not by CMake. For example if you define a variable ${MYVARIABLE_INCLUDE_DIR} or ${MYVARIABLE_LIBRARIES} is "INCLUDE_DIR" or "LIBRARIES" an extension interpreted by CMake or there is no difference if I call this variable ${MYVARIABLE_INCDIR} ?

4) How to do the same procedures (including a "personal" library) if you have a library that contains ten library files or more in the lib directory ?

5) And finally, when you type TARGET_LINK_LIBRARIES(myexecutable gmp), how do you know that the name of the library is "gmp". Why not "Gmp" or "GMP" ? Is the name of the library to put in this function just equal to the .a file minus "lib" and ".a" ? For example libgmp.a -> gmp ? If I want to link a library called libtestlolexample.a, do I have to type TARGET_LINK_LIBRARIES(myexecutable testlolexample) ?

Thank you very much.

Upvotes: 17

Views: 32550

Answers (3)

trenki
trenki

Reputation: 7363

You can use target_link_libraries(myexecutable mylib) to link to the library "mylib". The compiler will use its default way to find the specified library (e.g. it will look for libmylib.a on Linux). The compiler will only look in the link_directories(directory1 directory2 ...), so you could try that command to add the required directories to the search path.

When "mylib" is also compiled with CMake this will be recognized and everything should work automatically.

When you want the user to specify a directory you can use a cached CMake variable. set(MYPATH "NOT-DEFINED" CACHE PATH "docstring").

For more complex stuff it is very advisable to write a CMake find module that can be used with find_package. I suggest you take a look at the FindALSA.cmake which can be used as a good starting point.

The interesting part is at the end:

if(ALSA_FOUND)
  set( ALSA_LIBRARIES ${ALSA_LIBRARY} )
  set( ALSA_INCLUDE_DIRS ${ALSA_INCLUDE_DIR} )
endif()

mark_as_advanced(ALSA_INCLUDE_DIR ALSA_LIBRARY)

The ALSA_LIBRARY and ALSA_INCLUDE_DIR variables are user configurable and stored in the cache, while ALSA_LIBRARIES and ALSA_INCLUDE_DIRS as well as ALSA_FOUND get computed and are the ones that the user of the find module is supposed to use.

Typically one would use the find module like this:

find_package(ALSA REQUIRED)
include_directories(${ALSA_INCLUDE_DIRS})
target_link_libraries(myexe ${ALSA_LIBRARIES})

I'm sure you can adapt this for your personal library.

Upvotes: 17

Sam Hartsfield
Sam Hartsfield

Reputation: 1451

Usually when you want to link against a library that doesn't have a find_package module (e.g. it's an uncommon library, or it's your own library), then you can use the basic commands (the find_X commands) to set variables with the paths you need. Then you use those variables as with find_package (include_directories, target_link_libraries).

If you're going to be using this library from multiple packages, you may want to create a find_package module; basically it's using the same commands with certain conventions.

Either of these allow you to specify paths (in the CMake module) to look in, and they allow the user to override the paths (the variables show up as options in ccmake/cmake-gui).

I'd be glad to add an example of one or both of these methods, just let me know what you're looking for.

If you just want a quick-and-dirty solution, you could do this, but I wouldn't recommend it:

include_directories(/perso/testlib/include)
add_executable(myexecutable myexecutable.cpp)
target_link_libraries(myexecutable
    /perso/testlib/lib/testlib1.a
    /perso/testlib/lib/testlib2.a)

Regarding your question about target_link_libraries (#5), you can do it several ways. If you want you can provide the full name (e.g. target_link_libraries(myexe libfoo.a)), but I think it's better (more portable I suppose) to use the short name (e.g. target_link_libraries(myexe foo). You can also include linker flags; I'm not sure where I read it, but I think it may translate the -L and -l flags for different linkers.

For example, if I have a bunch of libraries in the same directory, and I know the names, I might find the directory, store it in a variable, and then do this:

# First, find and set TESTLIB_LIBRARY_DIR, e.g. with find_path
# ...

# This assumes the libraries are e.g. 'libtestlib1.a' and 'libtestlib2.a'
set(TESTLIB_LIBRARIES
    -L${TESTLIB_LIBRARY_DIR)
    -l testlib1
    -l testlib2)

add_executable(myexecutable myexecutable.cpp)
target_link_libraries(myexecutable ${TESTLIB_LIBRARIES})

If you want to make your own find_package module (like trenki mentioned, FindALSA.cmake seems to be a good starting point), you can use it by adding the directory to the CMAKE_MODULE_PATH; for example, if you put your module(s) in a cmake/modules/ subdirectory:

# Look for extra CMake modules in a subdirectory of this project
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/" ${CMAKE_MODULE_PATH})

One possible issue with FindALSA.cmake: I'm not sure CMAKE_CURRENT_LIST_DIR will work. So I think you should make this change (the second work for me in a module I wrote):

# Change this line
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)

# To this (with no path/extension it will search the CMake modules path):
include(FindPackageHandleStandardArgs)

And to get the usage of FIND_PACKAGE_HANDLE_STANDARD_ARGS, look at FindPackageHandleStandardArgs.cmake in the CMake Modules directory.

Upvotes: 5

Mythli
Mythli

Reputation: 6305

CMake has a good documentation.

  1. Static linkage (if i understand you correct) is archived by passing the STATIC keyword to add_library
  2. I would suggest to not do that (I'm not a CMake expert) but it sounds like the expense would be to large.
  3. There is no difference, ${MYVARIABLE_INCLUDE_DIR} ist just a variable name it whatever you want. But i would suggest that you follow the naming convention.
  4. One libary is always one .lib/.a file so there should be no problem just use the add_library& target_link_libraries& add_dependencies function.
  5. The library name is always the name that you pass to add_library. However Gmp or gMP would be the same as CMake is case intensitive

Upvotes: 0

Related Questions