2

I have a simple C++ project simple_test that depends on an external prebuilt library mylib.

The project file structure looks like this

CMakeLists.txt main.cpp external_dependencies/ libmylib.a 

With the Cmake file looking like this

make_minimum_required(VERSION 3.17) project(simple_test) set(CMAKE_CXX_STANDARD 17) add_executable(simple_test main.cpp) target_link_directories( simple_test PUBLIC external_dependencies/ ) target_link_libraries( simple_test mylib ) 

This builds and links fine.

What I would like to do though is have the project detect and obtain the mylib file if not present. When I say obtain, all I am attempting for now is to copy libmylib.a from another location into external_dependencies but a full implementation would involve more steps.

I found these relevant questions on stack overflow and the cmake manuals

so I am led to believe that I need to use add_custom_command and to add the lib file to a target.

I've created this custom command to copy the library into place and set up a target for the executable to depend on it.

add_custom_command( OUTPUT external_dependencies/libmylib.a WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND cp depsrc/libmylib.a external_dependencies/ COMMENT "CreatedLib" ) add_custom_target(mylib_target DEPENDS external_dependencies/libmylib.a ) add_dependencies( simple_test mylib_target ) 

This works to copy the file but is also executed on every build.

I've then tried using an IMPORTED library:

target_link_libraries( simple_test mylib_target ) add_library(mylib_target STATIC IMPORTED) set_property(TARGET mylib_target PROPERTY IMPORTED_LOCATION external_dependencies/libmylib.a ) add_custom_command( OUTPUT external_dependencies/libmylib.a WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND cp depsrc/libmylib.a external_dependencies/ COMMENT "CreatedLib" ) 

but this gives me an "no rule found" error

-- Configuring done -- Generating done -- Build files have been written to: /simple_test/cmake-build-debug gmake[3]: *** No rule to make target `external_dependencies/libmylib.a', needed by `simple_test'. Stop. 

What am I doing wrong?

0

2 Answers 2

2

Assuming that you keep the initial details relatively the same, you should be able to do something like this:

Set up the path to the source and destination:

set(LIB_SOURCE "depsrc/libmylib.a") set(LIB_DEST "${CMAKE_SOURCE_DIR}/external_dependencies/libmylib.a") 

Check if it exists, then use ${CMAKE_COMMAND} instead of cp for good compatibility practice:

if(NOT EXISTS ${LIB_DEST}) add_custom_command( OUTPUT ${LIB_DEST} COMMAND ${CMAKE_COMMAND} -E copy ${LIB_SOURCE} ${LIB_DEST} COMMENT "Copying libmylib.a to external_dependencies/" ) add_custom_target(mylib_copy_target DEPENDS ${LIB_DEST}) add_dependencies(simple_test mylib_copy_target) endif() 

Link the simple_test against the imported mylib:

add_library(mylib STATIC IMPORTED) set_property(TARGET mylib PROPERTY IMPORTED_LOCATION ${LIB_DEST}) target_link_libraries(simple_test mylib) 

Finally, set the directory where the library is located:

target_link_directories(simple_test PUBLIC external_dependencies/) 
Sign up to request clarification or add additional context in comments.

Comments

1

The ideal way to do this is to install the external library, and then use find_package in your project to find it, setting cmake prefix path if required. Ideally, the external library will have been built with CMake and will provide the necessary config files to enable this. If you yourself are building the dependent library, see, e.g., https://dominikberner.ch/cmake-interface-lib. I said "ideal", deliberately, because often the external library hasn't been built with CMake, or even if you control it, you don't have the time to do it the ideal way.

The practical way is to use file(COPY...) (docs) or file(COPY_FILE src_file dest_file) (docs, requires 3.21), early on in your top-level CMakeLists.txt, so that the library is available for you to use with target_link_libraries when required.

Note

Copying preserves input file timestamps, and optimizes out a file if it exists at the destination with the same timestamp

If you want to do something more sophisticated than simply copying a file, you are likely still better off looking at doing it in the configure stage, rather than at build time.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.