How to use CPack to pack several cmake build results? - c++

As I have to build both static and shared library for x86 and arm platform. So with the same CMakeLists.txt, I have to run it four times with different configuration. I want to use CPack to pack those libraries to one tar file. However, it seems that only the last cmake build results will be included in the tar file.
Is there any idea for this problem?
Here is part of my CMakeLists.txt:
install(FILES api_cpp.h api_c.h DESTINATION api_lib/include)
install(TARGETS lib
ARCHIVE DESTINATION api_lib/${lib_folder}
LIBRARY DESTINATION api_lib/${lib_folder})
INCLUDE(CPack)
SET(CPACK_GENERATOR "TGZ")

Obviously, you use a single-configuration generator -- meaning that you can't have more than one particular build configuration in the same build directory. Actually the problem exists even for the multi-configuration generators as well (at least for CMake < 3.16).
To make a package one ought to run CMake, which generates build files, then build a project, and finally can make a package (e.g., w/ make package). The last action runs CPack, which performs make install DESTDIR=<some-temporary-dir>, and then cpack just compress the directory into an archive. So, having a build directory with the only configuration it's impossible to have an archive with few of them.
To make your need possible you ought to run CMake 4 times doing install into the same location and then pack that directory into a package. It can be done with CMake+CPack, but IMHO easier to do w/ a trivial shell script :)

Related

reference dynamic libraries using relative path in CMakeLists

I have a project using some dynamic libraries. The generated executable runs well on my local machine. However, if I share it with others, the executable will still try to find dynamic libraries with the absolute path in my local machine, which of course do not exist in other machines. How can I resolve this issue by changing CMakeLists?
My current CMakeLists.txt file:
cmake_minimum_required(VERSION 3.24)
project(MyProject)
link_directories("libs/mac_arm64")
add_executable(MyProject main.cpp)
target_link_libraries(MyProject expat bz2 z geos_c)
When CMake builds libraries and executables, it (by default) embeds absolute RPATH into them. This allows to successfully find all libraries when run those executables on the build machine.
But those libraries and executables, which are created in the build tree, are not intended to be copied to other machine.
Instead, you should install those libraries and executables. Upon installation CMake strips their hardcoded RPATHs, which allows to distribute them.
Add to your CMakeLists.txt:
install(TARGETS MyProject DESTINATION bin/)
and build it with
mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX=../install
make
make install
This will install your project into install directory near the build. After installation you could pack content of install directory and send it to your customers/friends/whoever. CMake even provides cpack tool for easy packaging an installed project.
More about RPATH settings in CMake can be found in their wiki.

how can i make some install command run before compile process?

I will use install command in my CMakeLists like this:
install(DIRECTORY lib-mmm/src/infra/ DESTINATION /home/nick/infra FILES_MATCHING PATTERN "*.h")
this is command to install some directory to some place.
I want this run before other compile process.
but i found when i define it as install, it will be called only when make install, which is after make process.
how can i make install directory command run before real compile process?
Afaik there is no way to do this by using the same project. The install target depends on the targets being build and any dependency of building on the install target would result in a circular dependency.
There are alternatives though:
Use file(COPY)
Use execute_process to set up, build & install another cmake project during configuration. It can be problematic though to get cmake to use the same options for that build. This could also be refined by getting add_custom_command involved...
In your case though simply adding the correct include directory using target_include_directories will probably work better though.

installing dll which exist in target directory to install directory using cmake

I have a target in CMake which is a shared library (.dll) and it depends on some other dlls which is added to system using find_packages.
the came is used mainly in Windows with VS (1029)
other dlls are copied to target directory (for example release or debug) during a build on VC.
Now I want to add an install target.
I have this code:
set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/win-Install)
install(TARGETS myDLL RUNTIME DESTINATION bin CONFIGURATIONS Release)
This copy my dll to install directory but not the dependent libraries.
How can make sure that the install also copies all dependent libraries to install directory?
I tried to use a FILE(GLOB_RECURSE All_DLLS "${CMAKE_RUNTIME_OUTPUT_DIRECTORY }/*.dll")
but it did not work.
How can make sure that install copies all dependent libraries (*.dlls) to install directory?
Apparently,
FILE(GLOB_RECURSE All_DLLS "${CMAKE_RUNTIME_OUTPUT_DIRECTORY }/*.dll")
is run during cmake execution, but I need a command that works and detect *.dlls in build directory when install target in VS is runs.

Load shared libraries from lib directory in CMake?

I have downloaded a ROS2 demo from the examples repository.
Specifically, I have used minimal_subscriber and minimal_publisher.
I have ROS2 installed in /opt/ros2 and when I build these two examples with colcon build, it generates an install/ directory with lib/, shared/ and the other usual directory structure.
I can execute and run these demos perfectly fine with my current setup in my machine, but these executables link to libraries present in /opt/ros2, so when I want to execute them in another machine without ROS2 installed or I move my ROS2 installation in my machine, the executables cannot find the shared objects.
I've added a really simple script that adds all dependencies to install/lib when building but the executables don't seem to care, they aren't looking for shared libraries in the generated lib directory, they keep trying to search in /opt/ros2.
I believe this is something I should solve in CMake and it's not ROS2 specific, so, is there any way I can tell my generated executables to search in a diferent directory? (../lib or ./lib in my case)
If you are building them yourself (assumed since you mention CMake), you can set the RPATH in CMake (docs here). Specifically set the CMAKE_INSTALL_RPATH something like:
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
If you can't rebuild them, you can set LD_LIBRARY_PATH in your environment to where the libraries are located, or you can patch the executables themselves with an updated RPATH by using patchelf.
In order to get a relative RPATH rather than an absolute RPATH, use the $ORIGIN variable in your rpath spec. See "Recommendations" the the link above for more details.

gRPC C++ build on Windows 10 how?

I am having no end of trouble trying to build gRPC on Windows 10 using Visual Studio 2015 (C++) and cmake.
I have downloaded and unzipped grpc from GitHub, along with all its .gitmodules (and their .gitmodules, etc.) and unzipped them to their specified locations. When I cmake grpc, it complains about no CMakeLists.txt in cares/cares. grpc's .gitmodules specifies cares-1_12_0, and that includes no CMakeLists.txt file. What to do? The master version of cares/cares includes a CMakeLists.txt file, so I copied it into the -1_12_0 tree. Now it finds CMakeLists.txt, but then complains of other files that it can't find.
If I just use the master version of cares instead of 1_12_0 (hoping whatever incompatibility has been fixed by now), I get no more cares complaints. Another way that I have found to get past the cares complaints is to unzip c-ares-master.zip into grpc/third_part/cares/cares and then unzip c-ares-cares-1_12_0.zip in the same place. I figure that that way c-ares-master.zip will provide any files that c-ares-cares-1_12_0.zip is missing, and c-ares-cares-1_12_0.zip will overwrite any files with the same names with the -1_12_0 version -- but is this a good practice (copying a specific branch on top of the master version when a specific version is specified)? (I am not using git to download because it is not available or approved for use here, so I must traverse the dependencies manually.)
The next complaint is from protobuf 3.0.x: repeated_field_reflection.h not found, but this is only a Warning.
Then there are Errors thrown from benchmark about can't find GTEST_LIBRARY, GTEST_INCLUDE_DIR, and GTEST_MAIN_LIBRARY.
Do I need to build/install all these submodules (from bottom up) before I try to build grpc? Differences between the different modules' build procedures (and resulting build directory structures) suggest to me that the answer to this question should be 'no', but I am not sure. I understand that cmake provides support for recursive builds down a source tree (through all third_party dependencies) starting from a single root CMakeLists.txt (i.e., a single execution of cmake should build everything), so it would make sense for this ability of cmake to be used and that dependents' build directory structures should be consistent.
I note that grpc's .gitmodules requires protobuf 3.0.x, but it also lists bloaty, and bloaty's .gitmodules requires protobuf (presumably, the master version). Will using different versions of protobuf in different parts of the src tree (and building two versions of protobuf) cause problems? If so, what should I do when different parts of the tree require different versions of the same module?
Googletest is required in at least 3 places (grpc, bloaty, protobuf-master (required by bloaty, but not required by protobuf-3.0.x which is required directly by grpc)). Where should I set my GTEST_ROOT to point to, and how will that work with a module that expects it to be somewhere under its own third_party branch? How does one install Googletest after it has been built?
cmake looks for what looks like all (or many of) the standard C #include files. Many are found, and many are not found (I am building from VS2015 x64 Native Tools Command Prompt, so the applicable LIB and INCLUDE paths should be available; I've looked at them, and they appear reasonable.). If it searches for all of these by default, then I am guessing that not finding some should not be a problem (if they are not used by grpc or its dependencies), so I haven't chased them down. However, one that is not found is pthread.h (and I understand at least one module uses pthreads, but the next line of cmake output is "Found Threads: TRUE"). Another disturbing finding is "-- Check size of off64_t - failed" (It seems that such a value could be important for defining protobuf structures.) CMake also runs many tests. Some succeed; others don't. Should I be concerned with the test failures (which ones)?
I've also noticed that many of these modules change [almost] daily, so it occurs to me that dependency on a master version in the GitHub repository could break at any time. Has anyone built a C++ gRPC for Windows recently?
Any help or suggestions would be appreciated.
Can't comment directly to roger as I'm missing the required karma points, but I was also able to encounter the same issue on Windows 10. This was working in CMAKE 3.14 and then got broken in 3.19 when I was forced to update my Jenkins server for another reason.
When I use the following (networked, not preferred for this answer but preferred for peace of mind), it works reliably; use this if you have network access on your build machine.
# Builds gRPC based on GIT checked-out sources
ExternalProject_Add(grpc
PREFIX grpc
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/path/to/grpc"
CMAKE_CACHE_ARGS
-DgRPC_INSTALL:BOOL=ON
-DgRPC_BUILD_TESTS:BOOL=OFF
-DgRPC_BUILD_GRPC_RUBY_PLUGIN:BOOL=OFF
-DgRPC_PROTOBUF_PROVIDER:STRING=module
-DgRPC_PROTOBUF_PACKAGE_TYPE:STRING=CONFIG
-DgRPC_ZLIB_PROVIDER:STRING=module
-DgRPC_CARES_PROVIDER:STRING=module
-DgRPC_SSL_PROVIDER:STRING=module
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/grpc
DEPENDS c-ares protobuf zlib
)
If you can't do that, I had to do things the difficulty way by building each component individually, tracking their install location, then adding them as arguments to the ExternalProjectAdd...
# Builds c-ares project from the git submodule.
ExternalProject_Add(c-ares
PREFIX c-ares
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/path/to/cares"
CMAKE_CACHE_ARGS
-DCARES_SHARED:BOOL=OFF
-DCARES_STATIC:BOOL=ON
-DCARES_STATIC_PIC:BOOL=ON
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/c-ares
)
# Builds protobuf project from the git submodule.
ExternalProject_Add(protobuf
PREFIX protobuf
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/path/to/protobuf/cmake"
CMAKE_CACHE_ARGS
-Dprotobuf_BUILD_TESTS:BOOL=OFF
-Dprotobuf_WITH_ZLIB:BOOL=OFF
-Dprotobuf_MSVC_STATIC_RUNTIME:BOOL=OFF
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/protobuf
)
# Builds zlib project from the git submodule.
ExternalProject_Add(zlib
PREFIX zlib
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/path/to/zlib"
CMAKE_CACHE_ARGS
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/zlib
)
# the location where protobuf-config.cmake will be installed varies by platform
set(_FINDPACKAGE_PROTOBUF_CONFIG_DIR "${CMAKE_CURRENT_BINARY_DIR}/protobuf/cmake")
# if OPENSSL_ROOT_DIR is set, propagate that hint path to the external projects with OpenSSL dependency.
set(_CMAKE_ARGS_OPENSSL_ROOT_DIR "-DOPENSSL_ROOT_DIR:PATH=${OPENSSL_ROOT_DIR}")
# Builds gRPC based on locally checked-out sources and set arguments so that all the dependencies
# are correctly located.
ExternalProject_Add(grpc
PREFIX grpc
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/path/to/grpc"
CMAKE_CACHE_ARGS
-DgRPC_INSTALL:BOOL=ON
-DgRPC_BUILD_TESTS:BOOL=OFF
-DgRPC_BUILD_GRPC_RUBY_PLUGIN:BOOL=OFF
-DgRPC_PROTOBUF_PROVIDER:STRING=package
-DgRPC_PROTOBUF_PACKAGE_TYPE:STRING=CONFIG
-DProtobuf_DIR:PATH=${_FINDPACKAGE_PROTOBUF_CONFIG_DIR}
-DgRPC_ZLIB_PROVIDER:STRING=package
-DZLIB_ROOT:STRING=${CMAKE_CURRENT_BINARY_DIR}/zlib
-DgRPC_CARES_PROVIDER:STRING=module
-Dc-ares_DIR:PATH=${CMAKE_CURRENT_BINARY_DIR}/c-ares/lib/cmake/c-ares
-DgRPC_SSL_PROVIDER:STRING=package
${_CMAKE_ARGS_OPENSSL_ROOT_DIR}
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/grpc
DEPENDS c-ares protobuf zlib
)