Simplest way to change target name (dll name) of vcpkg library - vcpkg

I want to use some vcpkg libs in an plugin to closed source 3rd party product (e.g. AutoCAD or ArcGIS).
Chosen vcpkg libs have zlib as dependencies, but the 3rd party product also use zlib and it is another version of the lib. I can not replace original dll, so the easiest way will be to change the name of vcpkg lib into e.g. myzlib1.dll.
How can I easy add prefix or suffix to target (dll) name in vcpkg?
Is there an easy way to do this for all libs, so I can build my own subset of vcpkg libs, which have my own name prefix or suffix and I'm sure that they make no name conflicts to other libs?

It is possible but complicated since not all ports are build with CMake. You need to define a custom VCPKG_CHAINLOAD_TOOLCHAIN_FILE with all the required changes to CMAKE_(SHARED|STATIC)_LIBRARY_PREFIX_<LANG> CMAKE_FIND_LIBRARY_PREFIXES etc. This should than cover all ports which are built with CMake. For the remaining ports you probably need to use the port overlay feature.
So the answer to the question: No there is no easy way to change the suffix/prefix for all vcpkg ports. In your case static linkage to your dependents is probably the easy way.

Related

How to idiomatically add external library dependencies that use git and CMake to a git and CMake project?

I would like to know how to add external libraries into my project. Is there a standard way of doing so?
The way I do it and that I don't like is:
Have a folder called vendors where I add submodules e.g. boost, openssl...
I build the external libraries (as they come with a cmake to build in general).
I add a premake (I could have used a cmake) to each external library and I configure so I can see the project in VS as well as the cpp and the hpp files.
I don't like this because I do copy the binaries of the external libraries manually, hence if I delete the bin folder I can't build my solution just by clicking build but I have to build the external libraries first using there cmake and then I copy the binaries manually to the bin/ folder of my solution.
Could you please give me a "standard" way I can do this? I feel like there could be better ways by just using to the max the CMake that comes with the external library. Also, I don't like changing the external libs too much, I just want to be able to update them anytime and everything works without me touching stuff.
How can this be done?
One approach is to use CMake's FetchContent functionality.
The FetchContent module allows specifying Git repositories of CMake projects to fetch at configure time. The default setting assumes that that repository has a CMakeLists.txt file at the repo's root directory. It clones the repo to a default (but configurable) location, and then just calls add_subdirectory() on the cloned directory.
You can read about how to use it in the reference documentation, and you can read about how that approach compares with some other CMake-supported approaches for using dependencies in the official Using Dependencies Guide. Do brace yourself when reading the reference docs, though. They're not designed to be like a beginner-friendly tutorial, and since FetchContent is built upon another module called ExternalProject, some of the docs for FetchContent just point you to go read sections from the ExternalProject docs. Be prepared to do a bit of digging.
Here's a basic example I used in a project at one point.
include(FetchContent)
FetchContent_Declare(
range-v3
GIT_REPOSITORY git#github.com:ericniebler/range-v3.git
GIT_TAG "0.12.0" # https://github.com/ericniebler/range-v3/releases
GIT_SHALLOW TRUE
GIT_PROGRESS ON
SYSTEM
)
# more `FetchContent_Declare`s (if any). They should all be declared
# before any calls to FetchContent_Make_available (see docs for why).
FetchContent_MakeAvailable(range-v3)
# more `FetchContent_MakeAvailable`s (if any).
FetchContent in some ways is designed to be a little bit "low level". It has a lot of machinery and customization points. If your project is super simple, you might find it useful to try out a CMake-external wrapper module called "CPM" (CMake Package Manager) that attempts to cater to sensible defaults for more common, simple use-cases.
If you use FetchContent or CPM, be aware that since they eventually just call add_subdirectory, you might need to take some steps to avoid naming conflicts of target names and CMake variable names between your CMake configs and the CMake configs of the dependencies you pull in. For more info, see How can I avoid clashes with targets "imported" with FetchContent_MakeAvailable?.
As others have mentioned, you can also look into using package managers like vcpkg or Conan. I don't know much about those so I can't comment.

How to install the C++20 range library from github

I would like to use the range-v3 library in my project, but i don't understand how. The installation description says the following:
This library is header-only. You can get the source code from the
range-v3 repository on github. To compile with Range-v3, just #include
the individual headers you want.
Does that mean I can copy and paste the needed header files and add the filepath to my CMake file? I am a bit confused, because I never included third party library.
Note: please see hythis' answer for a better solution.
Does that mean I can copy and paste the needed header files and add the filepath to my CMake file?
Basically, yes. First git clone to <path_to_range_v3>. Then include these lines into CMakeLists.txt:
add_library(range_v3 INTERFACE IMPORTED)
set_target_properties(range_v3 PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES <path_to_range_v3>/include)
target_link_libraries(your_target PUBLIC range_v3)
I'm not sure why Evg suggested what they did, I don't even think in 2019 you were forced to create your own CMake interface with ranges-v3 (see here, the file existed way before hand). Regardless, don't use Evg's solution, ranges-v3 is a good header only library, and in order for a header only library to be good it must provide CMake integration.
Header only libraries do not mean the authors do not provide CMake support, or even avoid CMake themselves. Bad authors do this, as you've probably experienced by having to ask this question in the first place.
To properly integrate with Ranges V3, use a packagemanager (though some package managers screw the process up depending on how their custom CMake files are configured) such as Conan or vcpkg and integrate with their respective CMake solutions, or add the project as a git submodule (though you could git clone it as well) then in your CMakeLists.txt:
add_subdirectory([path to submodules]/range-v3)
...
target_link_libraries(my_target [SCOPE] range-v3::range-v3)
It can be hard to figure out actual targets for libraries if the authors don't spell out how to use their projects in a CMake project, and I don't blame any one making an SO post about it, it's a pain.
Generally if the project has a CMakeLists.txt file, it probably has static-library/sub_directory cmake integration, but some libraries only have install targets, thus are unusable when baked into your source code with out editing their CMakeLists.txt
To check if this is the case, or if you can actually use the targets, if you can't find any CMake documentation about how to use the library (which I couldn't) do the following:
Look inside the CMakeLists.txt file
Find a project alias usually in the form of project_name::project_name. This is how I found range-v3's project alias.
If you can't find alias (via searching for ::), find the actual target name for the library (and try to use this directly), sometimes this isn't exported though (hidden in a sub directory from the top cmake file). OpenCV doesn't use :: for example, and instead each component target is marked with opencv_[component name] but still exported.
If the project has not been configured to be properly used as a submodule and is otherwise meant to be used as a static library, submit an issue or PR to the given repository, this is a bug.

Are exported (installed) cmake targets distributable?

I'm working on a project with a lot of external dependencies, which are included in the project tree. I would like to pre-build all of the dependencies and share the importable targets within the project tree.
I was planning to use cmake install with a CMAKE_INSTALL_PREFIX in the source tree, and use CMAKE_PREFIX_PATH to reference it for find_package. However, I'm beginning to wonder how maintainable this strategy is going to be? For example here's something I noticed in one of the installed cmake scripts:
${CMAKE_PREFIX_PATH}/lib/cmake/glfw3/glfw3Targets.cmake:
set_target_properties(glfw PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include"
INTERFACE_LINK_LIBRARIES "/usr/lib/x86_64-linux-gnu/librt.so;/usr/lib/x86_64-linux-gnu/libm.so;dl;/usr/lib/x86_64-linux-gnu/libX11.so;-lpthread"
)
It seems really suspicious to me that all of those link libraries are fully resolved to paths on the host machine.
I guess the question is: Are cmake installs to a prefix meant to be distributable and this is just a bad example, or are they meant to be tied to the machine you "install" them on? Ie. Is prefix really meant to just relocate where on the system things are supposed to be "installed", and my hope to use it as a shared package manager likely to be problematic?
Yes, EXPORT'ed CMake targets can be "distributable", but the project should follow some principles for achieve that.
If you link with a (external) library, but do not want export file to contain absolute path to it, then do not pass absolute path directly to target_link_libraries.
In case a linked library is shipped with a compiler (e.g. m or rt), things are simple: just pass the library's name to the target_link_libraries.
In case a linked library YYY comes from other package and is detected by find_package(YYY), this implies several things:
Script FindYYY.cmake or YYYConfig.cmake should return IMPORTED target. If this is not true, you may try to wrap its results into IMPORTED target.
target_link_libraries should use this IMPORTED target.
Script XXXConfig.cmake, shipped with your project, should use find_dependency(YYY) for discover a library on a user machine.
For find_dependency(YYY) work, a user machine should have FindYYY.cmake or YYYConfig.cmake script. Alternatively, you may ship FindYYY.cmake with your project, and adjust CMAKE_MODULE_PATH variable before find_dependency() call (in your XXXConfig.cmake).

How to use external DLLs in CMake project

I've been searching over the internet but I couldn't find anything that would answer my question (or I don't know what to search for).
Anyway here's my issue:
I want to use 3rdParty libraries (.dll files) in my CMake project. Library (https://github.com/pitzer/SiftGPU) that I want to include is open source and is also available in binary which I would like to use and also uses CMake as build tool if that's relevant.
I hope I was clear enough.
First, edit your CMakeLists.txt to include your third party library. You'll need two thing: path to header files and library file to link to. For instance:
# searching for include directory
find_path(SIFTGPU_INCLUDE_DIR siftgpu.h)
# searching for library file
find_library(SIFTGPU_LIBRARY siftgpu)
if (SIFTGPU_INCLUDE_DIR AND SIFTGPU_LIBRARY)
# you may need that if further action in your CMakeLists.txt depends
# on detecting your library
set(SIFTGPU_FOUND TRUE)
# you may need that if you want to conditionally compile some parts
# of your code depending on library availability
add_definitions(-DHAVE_LIBSIFTGPU=1)
# those two, you really need
include_directories(${SIFTGPU_INCLUDE_DIR})
set(YOUR_LIBRARIES ${YOUR_LIBRARIES} ${SIFTGPU_LIBRARY})
endif ()
Next, you can do the same for other libraries and when every libraries are detected, link to the target:
target_link_libraries(yourtarget ${YOUR_LIBRARIES})
Then you can configure your project with CMake, but as it doesn't have any magic way to find your installed library, it won't find anything, but it'll create two cache variables: SIFTGPU_INCLUDE_DIR and SIFTGPU_LIBRARY.
Use the CMake GUI to have SIFTGPU_INCLUDE_DIR pointing to the directory containing the header files and SIFTGPU_LIBRARY to the .lib file of your third party library.
Repeat for every third party library, configure again and compile.

CMAKE for modular c++ framework

I'm refactoring a large platform independent c++ framework so that it's libraries and execuables no longer have to be in the same directory (or even repository) and it is proving quite challenging. The framework was currently used only by me and it should now address our whole working group so I have to keep it as modular and as automatized as possible.
My basic structure looks like this
apps/
app1, app2, ...
libs/
core, lib1, lib2, ...
bin:
app1, app2, libcore, liblib1, liblib2, ... (on NIX)
app1.exe, app2.exe, core.dll, lib1.dll, lib2.dll, ... (on Windows)
Apps depend on libs, and all libs depend on the core lib. This all works fine in the same root directory and with the add_subdirectory mechanism.
Project dependencies were handeled by the order in which I was calling add_subdirectory: first libs (core being the first), then apps. Cmake was kind enough to set ${core_SOURCE_IR} to the respective directory and all binaries (libs and apps) were generated in the same directory.
What I need advice with is:
should I move to a find_package based approach (write for each lib and FindLib.cmake file)
how the apps and libs will find each other
where to put the binaries
how to pass along include directories of dependent targets
ExternalProject_Add ?
Thank you
I'd recommend using INSTALL(TARGETS... along with INSTALL(EXPORT...
For full details, run:
cmake --help-command INSTALL
FIND_PACKAGE is generally used to find an external project which is already installed (and which wasn't installed with CMake's INSTALL(EXPORT... command) and ExternalProject_Add is used to download, configure, build and install an external project.
If you use INSTALL(EXPORT... with each of your libs and exes, and then just INCLUDE the installed <target>.cmake in your main CMakeLists.txt, these will become available as proper CMake targets, with their dependencies per configuration already set.
As to where to install these export files - that's up to you, but as long as the path you specify is the same place you use when you INCLUDE the file later, it should work fine.
First, you can add_subdirectory()es in any order without caring about dependencies. CMake handles them when all CMakeLists.txt are parsed.
Second, if you wish any your lib or app to be buildable stand-alone, you certainly should use something like find_package(). It can be find_library() and find_file(lib.h) for simple cases.
In this case after find_package() invocation you will have LIB_INCLUDE_DIRS, LIB_LIBRARY_DIRS, LIB_LIBRARIES variables defined, which can be passed to include_directories(), link_directories() and target_link_libraries() respectively. That's how apps will find libs.
As for where to put binaries - in *NIX it's wide practice to place them into ${CMAKE_INSTALL_PREFIX}/bin.
Please comment on this answer, if there is something unclear for you.