Reputation: 1379
I want to rename certain executables in CMakeLists.txt
but also want symbolic links from the older names to new files for backward compatibility. How can this be accomplished on systems that support symbolic links?
Also what are the alternatives for system that does not support symbolic links?
Upvotes: 26
Views: 64172
Reputation: 2215
There is file(CREATE_LINK <original> <linkname> SYMBOLIC)
since CMake 3.14. It creates a symlink at configure time.
Not sure this is what OP asked for, but this is what I was looking for when found this question.
Upvotes: 1
Reputation: 287
If what you are looking for is links for your executables and library files based on version numbers you can let CMake take care of that for you by setting the appropriate properties SOVERSION
and VERSION
on your targets:
The following CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(version_links C)
add_library(mylib SHARED lib.c)
set_target_properties(mylib PROPERTIES
PUBLIC_HEADER lib.h
VERSION 3.2.1
SOVERSION 3.2
)
add_executable(exec exec.c)
target_link_libraries(exec PRIVATE mylib)
set_target_properties(exec PROPERTIES
VERSION 3.2.1
)
install(TARGETS mylib exec)
produces the following tree inside CMAKE_INSTALL_PREFIX
:
${CMAKE_INSTALL_PREFIX}
├── bin
│ ├── exec -> exec-3.2.1
│ └── exec-3.2.1
├── include
│ └── lib.h
└── lib
├── libmylib.so -> libmylib.so.3.2
├── libmylib.so.3.2 -> libmylib.so.3.2.1
└── libmylib.so.3.2.1
References:
Upvotes: 0
Reputation: 526
You can create a custom target and use CMake to create symlinks
ADD_CUSTOM_TARGET(link_target ALL
COMMAND ${CMAKE_COMMAND} -E create_symlink ${target} ${link})
This will only work on systems that support symlinks, see the documentation.
Before CMake v3.14, this did not work on Windows. In v3.13, support for Windows was added.
Upvotes: 35
Reputation: 4677
Lets say you need to create a link in binary dir to a target located in source directory.
You can try file CREATE_LINK since version 3.14
${CMAKE_COMMAND} -E create_symlink is accessible at Windows since 3.17
You can use execute_process since early cmake versions:
if(WIN32)
get_filename_component(real_path "${dirname}" REALPATH)
string(REPLACE "/" "\\" target_path "${real_path}")
execute_process(
COMMAND cmd /C mklink /J ${dirname} "${target_path}"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
)
else()
execute_process(COMMAND "ln -s ${CMAKE_CURRENT_SOURCE_DIR}/${dirname} ${CMAKE_CURRENT_BINARY_DIR}/${dirname}")
endif()
Upvotes: 5
Reputation: 2425
When I build, I create a symlink to the compile_commands.json
. This helps clangd and vscode's intellisense.
Here's a full working example of what worked for me.
add_custom_command
is what creates the symlink.
cmake_minimum_required(VERSION "3.1.0")
# project name
project("a-s-i-o")
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -std=c++17 -pthread -Wall -Wextra -Werror -pedantic -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function -Wno-unused-private-field"
)
# Create `compile_commands.json` file.
#
# This is required by `clangd` to find the header files. For this to work, this
# file must be in the root of the project. Therefore, we create a symbolic link in the root that
# points to the `compile_commands.json` file created by CMake in the `build` directory.
#
# This specific commands creates the file in the build directory. The command `add_custom_command`
# creates the symbolic link in the root directory.
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
add_executable(x main.cpp)
target_include_directories(x PUBLIC "/usr/local/include/asio-1.20.0/include")
# When target `x` is built, a symlink will be created to
# `build/compile_commands.json`. This is required for clangd to be able to find
# the header files included in the project.
add_custom_command(TARGET x
COMMAND ${CMAKE_COMMAND} -E create_symlink "${CMAKE_CURRENT_BINARY_DIR}/compile_commands.json" "../compile_commands.json"
DEPENDS compile_commands.json
VERBATIM ON
)
# Print success message to the console
add_custom_command(TARGET x POST_BUILD
COMMAND echo "Created symlink pointing to `compile_commands.json`"
DEPENDS compile_commands.json
VERBATIM ON
)
Upvotes: 2
Reputation: 194
I've added the check to @ulidtko's approach, so symlink doesn't overridden on every rebuild unconditionally:
install(CODE "if (NOT EXISTS ${link})
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink \
${target} \
${link})
endif()" )
Upvotes: 1
Reputation: 49
I've struggled with this a few different ways with the above responses in order to install '.so.#' files that refer to other '.so.#.#' files. I've had success by not introducing a link to the file, but by installing the '.so.#.#' file as the '.so.#' file.
I.e. instead of
install(
FILES
.../libmpi.so.12.0
DESTINATION lib
)
install(CODE
"EXECUTE_PROCESS( ${CMAKE_COMMAND} -E create_symlink lib/libmpi.so.12.0 lib/libmpi.so.12)")
Which didn't quite work for me even. I have instead had success by doing this.
install(FILES
.../libmpi.so.12.0
RENAME libmpi.so.12
DESTINATION lib
)
Not 'exactly' the same, but sufficient. Don't defeat the problem, solve the problem.
Upvotes: 0
Reputation: 15642
Another way to do it:
INSTALL(CODE "execute_process( \
COMMAND ${CMAKE_COMMAND} -E create_symlink \
${target} \
${link} \
)"
)
This way the symlinking will be done during make install
only.
Upvotes: 33
Reputation: 1996
Another method that is a bit more verbose and only runs on install:
macro(install_symlink filepath sympath)
install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ${filepath} ${sympath})")
install(CODE "message(\"-- Created symlink: ${sympath} -> ${filepath}\")")
endmacro(install_symlink)
Use it like this (similar to ln -s):
install_symlink(filepath sympath)
Upvotes: 21