简体   繁体   中英

How to make cmake find a shared library in a subfolder

I'm trying to learn how to make a shared library. And the following seems to work (please comment if you have some feedback to this method, I basically have no idea what I'm doing).

In my library project, I've put the header files into a folder named "include", and the source files into "src".

My library's CMakeLists.txt:

cmake_minimum_required(VERSION 2.4.0)

project(mycustomlib)

# Find source files
file(GLOB SOURCES src/*.cpp)

# Include header files
include_directories(include)

# Create shared library
add_library(${PROJECT_NAME} SHARED ${SOURCES})

# Install library
install(TARGETS ${PROJECT_NAME} DESTINATION lib)

# Install library headers
file(GLOB HEADERS include/*.h)
install(FILES ${HEADERS} DESTINATION include)

My application's CMakeLists.txt:

cmake_minimum_required(VERSION 2.4.0)

project(myprogram)

# Find source files
file(GLOB SOURCES src/*.cpp)

# Create executable
add_executable(${PROJECT_NAME} ${SOURCES})

# Find and link library
find_library(MYCUSTOMLIB mycustomlib)
target_link_libraries(${PROJECT_NAME} ${MYCUSTOMLIB})

And this is working . The problem is that I want to put both the headers and the library into subfolders (specifically: /usr/local/include/mycustomlib/ for the headers, and /usr/local/lib/mycustomlib/ for the library).

So this is my attempt:

My library's new CMakeLists.txt:

cmake_minimum_required(VERSION 2.4.0)

project(mycustomlib)

# Find source files
file(GLOB SOURCES src/*.cpp)

# Include header files
include_directories(include)

# Create shared library
add_library(${PROJECT_NAME} SHARED ${SOURCES})

# Install library
install(TARGETS ${PROJECT_NAME} DESTINATION lib/${PROJECT_NAME})

# Install library headers
file(GLOB HEADERS include/*.h)
install(FILES ${HEADERS} DESTINATION include/${PROJECT_NAME})

My application's new CMakeLists.txt:

cmake_minimum_required(VERSION 2.4.0)

project(myprogram)

# Find source files
file(GLOB SOURCES src/*.cpp)

# Create executable
add_executable(${PROJECT_NAME} ${SOURCES})

# Find and link library
find_library(MYCUSTOMLIB mycustomlib/mycustomlib)
target_link_libraries(${PROJECT_NAME} ${MYCUSTOMLIB})

And this is not working. Now, I'm forced to specify the .so file of the library like this:

find_library(MYCUSTOMLIB mycustomlib/libmycustomlib.so)

How come?

I'll deal with your actual problem first and offer additional comments after that. Technically speaking, you are asking CMake to find a library named mycustomlib/mycustomlib , but what you really want to say is you want find mycustomlib and it can be found in a subdirectory called mycustomlib . A couple of alternative ways to call find_library() to achieve this for your second case would be:

find_library(MYCUSTOMLIB mycustomlib PATH_SUFFIXES mycustomlib)
find_library(MYCUSTOMLIB mycustomlib PATHS /usr/local/lib/mycustomlib)

The latter is making more assumptions than it should about where you have the library installed, so I'd favour the first option. The first option assumes CMake would already find libraries in /usr/local/lib, which it seems it is from your question. You can influence where CMake looks for libraries by modifying CMAKE_PREFIX_PATH and CMAKE_LIBRARY_PATH . I'd expect either of the above options to make your second case work.

Now to other observations. You've requested a very old minimum CMake version in the first line of each of your CMakeLists.txt files. You probably want to consider at the very least making this 2.8 (personally, I'd suggest more like 3.2 or later, but it depends on what your project needs to support).

You have used file globbing to obtain your list of sources and headers. This is not robust and should generally be avoided (see a discussion of this here ). You will see plenty of example code use method this for simplicity, but it is not recommended for real world projects (the CMake documentation even says not to use it ). Explicitly list out your source and header files individually if you want robust builds.

If you are happy to require CMake 2.8.11 or later (and you should be these days), rather than calling include_directories() which makes everything pick up the header search path you specified, you should prefer to attach the search path requirement to the target that needs it. You do this with target_include_directories() . The equivalent of your code above would be:

target_include_directories(${PROJECT_NAME} PUBLIC include)

This gives much better control of your inter-target dependencies as your project grows in size and complexity. For a more in-depth discussion of this topic, see this article and perhaps also this one (disclosure: I wrote both articles).

Are your library and program totally separate source code repositories? Can they be built in the same project? You can build multiple targets in one CMakeLists.txt file. The project name doesn't have to have any relationship to the names of any of the targets (you often see the PROJECT_NAME variable re-used for the target name in simple examples, which is unfortunate since it suggests a relationship between the two, but for all but simple projects this won't be the case). If they are in the same repository, building them together would be a much simpler build since you wouldn't have to install the library for the executable to find it and link to it.

If they must be built in separate projects, then something like the following for the application's project should get you close:

cmake_minimum_required(VERSION 2.8.11)
project(myprogram)

# List your program's sources here explicitly
add_executable(myprogram src/foo.cpp src/bar.cpp)

# Find and link library
find_library(MYCUSTOMLIB mycustomlib PATH_SUFFIXES mycustomlib)
target_link_libraries(myprogram PUBLIC ${MYCUSTOMLIB})

# Find library's headers and add it as a search path.
# Provide the name of one header file you know should
# be present in mycustomlib's include dir.
find_path(MCL_HEADER_PATH mycustomlib.h PATH_SUFFIXES mycustomlib)
target_include_directories(myprogram PUBLIC ${MCL_HEADER_PATH})

For extra points, you could try to confirm that the header path is in the same area as the library by checking the common path prefix, or you could just derive the MCL_HEADER_PATH from the MYCUSTOMLIB path by assuming a directory structure. Both approaches have advantages and drawbacks. If you want to explore the latter, the get_filename_component() command will be your friend.

Hopefully that points you in the right direction.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM