Issue
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?
Solution
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/)
Answered By - neutron02 Answer Checked By - Terry (WPSolving Volunteer)