gRPC for C++ on Windows, dependencies - c++

This is going to be a little long of an introduction, but I think it i neccessary for you to understand what I've already tried.
I am currently trying to set up a gRPC Client with C++, after i already set up a Server and Client in Python with no problem. However for C++ the building of gRPC is just evil. With the resources form the offivial git repository I was able to build gRPC (or so i thought) but when I then tried to build my project with Cmake i got an error that the gRPCTargets.cmake is missing. Tracing this back I found that I had to build gRPC itself with all the dependencies as packages instead of submodules. So I started by downloading C-Ares and building it. No Problem here. Next I tried reconfiguring gRPC with the new c-ares directory variable set and type package set. Now i encountered a Problem that the in c-ares-config.cmake an include directory is specified which does not exist at all.
get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE)
macro(set_and_check _var _file)
set(${_var} "${_file}")
if(NOT EXISTS "${_file}")
message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !")
endif()
endmacro()
set_and_check(c-ares_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include")
include("${CMAKE_CURRENT_LIST_DIR}/c-ares-targets.cmake")
For me the Path with /../../../ doesn't make any sense but since it's automatically generated and I am pretty much a noob using Cmake I cannot say what would be correct there. All i know is that there is no folder named include inside any of the c-ares folders. I tried removing the set_and_check(...) line, which removes the error, but now I am asked for a c-ares-targets.cmake which cannot be found.
I am pretty much stuck here. I would highly appreciate any help or ideas fixing this.
Maybe there is an option of getting a precompiled gRPC-resource for C++ on windows, but was unable to find any sources.

Related

How could one install dependencies using CMake?

I have been trying to figure out the best way to handle dependencies in my C++ projects. For smaller libraries, like fmt, it is not too difficult to just add the following:
include(FetchContent)
FetchContent_Declare(FormatLib
GIT_REPOSITORY "https://github.com/..."
GIT_TAG "..."
)
FetchContent_MakeAvailable(FormatLib)
However, it is undesirable to have the project downloaded into the build directory every time with larger dependencies, for example, the Vulkan Loader which depends on other things.
What I would like would be the ability to do something like, before or at configure time of my main project, to download, configure, build and install a library system wide. I do not know if this is a feature possible with CMake but any help would be appreciated.
I also know that the ExternalProject module has existed in CMake for a long time now, and would be perfect for what I want, I think... if I were able to use it to install a library before I would then call find_package inside the same CMakeLists.txt
I purchased and read a considerable amount of the "Professional CMake 8th Edition" but still don't know if such a feature or technique exists in CMake.
I should clarify that I don't need the Vulkan loader, I was just giving an example. In the case of the Vulkan loader, if you have the SDK already installed, you can use the built in find_package command. My question is whether there's a way to populate such a library before hand. There are specific libraries that I haven't been able to find using package managers such as Conan and it seems like the best possible solution would be to actually just pull the source straight from an online git repo, build and install.
So in conclusion, what I would like to be able to do is the following: Write a CMakeLists.txt that details all the dependencies of a project, possibly searches for the dependencies using find_package, if they're not found, it installs them system wide so that from there on out, every build of said project or similar project on the system has access to the package installed.
Any advice, insight or suggestions on how I can mitigate this problem or even how my desired development strategy is flawed would be appreciated.

CMake not finding package that is clearly there

I am trying to build a project via cmake in qtcreator, but am having trouble with the external package dependencies.
There have been several packages that it could not find, but I added symlinks to the actual file locations into the directory cmake was looking in, afetr which they worked fine.
However, this one library libopencv_viz.so.3.2.0 isn't cooperationg with me. I added the symlink and visually verified that the file/link is in the correct location, but cmake is still telling me that it cannot find the file, and I have no clue how to solve this. As I stated in a prior post, I am still just learning cmake right now, so I have absolutely no clue why it would not be able to find a package that is verifiably in the correct location.
CMake Error at /usr/share/OpenCV/OpenCVModules.cmake:192 (message):
The imported target "opencv_viz" references the file
"/usr/lib/x86_64-linux-gnu/libopencv_viz.so.3.2.0"
but this file does not exist. Possible reasons include:
The file was deleted, renamed, or moved to another location.
An install or uninstall procedure did not complete successfully.
The installation package was faulty and contained
"/usr/share/OpenCV/OpenCVModules.cmake"
but not all the files it references.
Creating symlinks by hand suggests you have an incomplete installation. Clean up your manual symlinks, and figure out what's wrong with your installation.
It is normal on Linux that the .so.x.y.z with the full numeric version is the runtime library. That is, the file that is required for applications to run. The version number ensures that the application loads the same library that it was built against.
The .so symlink to .so.x.y.z is for the build chain. When the compiler (linker, really) goes to link against libopencv_viz, it will search for libopencv_viz.so, resolve the symlink to versioned file, and link that.
Many distributions (including Ubuntu) separate the runtime libraries from the development components. My guess is that you've installed the package named libopencv-viz3.2, but not the one named libopencv-viz-dev.

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
)

Does CMake has a "find-or-download-and-run-build-command" mechanism?

CMake has a find_package() backed by a bunch of FindXYZ scripts (which you can also add to).
What mechanism, if any, is available to me to tell cmake: "Find this package, and if you haven't found it, download it and trigger its build" - with the downloading and building part also backed by per-package scripts or settings (so that downloading could be with wget or git clone, building could be with cmake or maven or a package-specific command, etc.) ?
Yeah, I was bitten by that Friday.
So, CMake has an ExternalProject directive, meant for exactly that, get/update if necessary, configure, build and install this and that external project. Awesome!
Sadly, CMake isn't that awesome.
You can't use the target defined by ExternalProject as a library in target_link_libraries. I've really tried to.
The basic problem is that the updating, building and installation of the external project happens at build time, whereas CMake insists on only using libraries that it found during pre-build (i.e. during the CMake run); you can't re-detect stuff while running make/ninja/msvc… .
You can define a custom target, tell it where the .so you'd want to link against later will be, and try to coerce CMake into believing you without checking at pre-build. Sadly, at least in the CMake versions I had, that broke dependency tracking, so that it simply didn't build the external library, because nothing needed it.
From the error messages you get when trying to use an external project in target_link_library, it seems CMake assumes you'd only want to install tools you need at build time that way, not libraries. A bummer.
You can roll your own version of download-on-demand using execute_process() (which runs on the CMake configure step) with ${CMAKE_COMMAND} as the command invoked on a CMakeLists.txt containing ExternalProject_Add().
You could even either configure_file() the CMakeLists.txt to fill out custom variables or dynamically create the CMakeLists.txt file.

Using CMake to find dependencies in an application-specific subfolder

In spite of many years of coding large-scale C++ applications, I do not understand how find_package is supposed to work in a medium-size CMake project, ASSUMING that I want to build the source to dependent packages myself and not simply rely on large systems like opencv, pcl or boost being installed somewhere in a system folder. I can't can't believe that I'm the only person in the world who has shipped multiple OpenCV and other open-source apps, has worked with meta-build systems like NAnt and SCons on major game projects, yet can't understand the most basic things about how CMake works or find a tutorial answering these questions.
In the past, I have essentially hacked around not understaning find_package by setting all the foo_DIR values by hand as CMake complains until I get a working folder.
I would like to run through a simple example which I'm working on right now, and dearly hope someone can explain what I'm doing so wrong.
Firstly, some assumptions:
I want to build everything for both MacOS and Windows, ideally via CMakeGUI. MacOS should build XCodeProjects and Windows should build Visual Studio Solutions.
Where there are dependencies, I want to compile them myself, so I have debug symbols and can modify the dependency source (or at least debug into it.)
No installation of pre-built binaries into system folders, i.e. no use of sudo port install opencv/pcl, etc on mac.
I have multiple projects, and prefer to keep a project and its dependencies in a single folder.
For the purposes of a concrete example, suppose I am building this project, although it's an arbitrary choice to illustrate the process and confusion I suffer:
https://github.com/krips89/opendetection
This lists dependencies, which I have intentionally reordered here so that I can take them in order, as follows:
find_package(OpenCV REQUIRED)
find_package(Eigen REQUIRED)
find_package(Boost 1.40 COMPONENTS program_options REQUIRED )
find_package(PCL REQUIRED)
find_package(VTK REQUIRED)
I would like to have all of these dependencies downloaded and configured in a single path (let's say c:\src on Windows, and ~\src on Mac for simplicity), NOT in a system path. Assume that the actual folder is a sub-folder for this project, and no a sub-folder for all projects. This should also allow for side-by-side installation of multiple projects on the same computer.
Taking this one step at a time:
(1) I clone openCV from https://github.com/opencv/opencv, sync to tag 3.1, configure into the folder opencv_build folder, build and install into opencv_install. I've done this so many times it's pretty straightforward.
(2) As above, but for eigen (although building for eigen doesn't actually do anything s it's a template library. I install to a folder eigen_install
Taking directory shows a series of folders for downloaded dependencies. I have assumed a convention where , and are source repos, and their following _build folders are the "WHere to build the binaries" folders in CMakeGui.
$ ls
boost_1_40_0 opencv opendetection_build
eigen opencv-build opendetection_data
eigen_build opencv_contrib pcl
eigen_install opendetection
All good so far, now let's try to configure opendetection and generate a solution into opendetection_build, and find pendetection's dependencies from within the ~/src folder, that is for the first two dependencies, I hope to find opencv and eigen in the opencv-build and eigen-build folders.
OpenCV immediately fails, as expected, saying:
Could not find a package configuration file provided by "OpenCV" with any of the following names:
OpenCVConfig.cmake
opencv-config.cmake
Add the installation prefix of "OpenCV" to CMAKE_PREFIX_PATH or set "OpenCV_DIR" to a directory containing one of the above files. If "OpenCV" provides a separate development package or SDK, be sure it has been installed.
That's good, because I want to explicitly tell CMake to look for dependent packages under my ~/src folder. Question: Is the use of CMAKE_PREFIX_PATH=/users/foo/src the recommended way to accomplish what I want - looking for all sub-packages under a specific path?
Following this, CMake finds OpenCV (good), and sets OpenCV_DIR = /Users/foo/src/opencv-build.
Question: Given that I have made an "install" to opencv-install (using CMAKE_INSTALL_PREFIX and building the Install Target Of OpenCV, shouldn't it find OpenCV in the opencv-install folder not opencv-build?
Moving on to eigen, I have configured and built eigen, and installed it to ~/src/eigen-install, which since it is a subfolder of CMAKE_PREFIX_PATH (~/src) I might expect to be found. But it doesn't seem to be. Can somebody explain to me what I'm not understanding? Particularly given that Eigen in a template library, and that there are at least three folders (eigen, eigen_build and eigen_install) under CMAKE_PREFIX_PATH which I would have thought CMake would find something in, I assume I must be doing something wrong here. I KNOW from past experience, I can set EIGEN_INCLUDE_DIR by hand in CMakeGUI by hand, and continue hacking forth, but that just seems wrong.
I'm more than willing to write up a web page explaining this for future people as dumb as me if one does not already exist, although I can't understand how use of CMake for basic project configuration and generation is apparently so obvious to everyone but so opaque for me. I have actually been using CMake for some years, usually by just manually setting Boost_INCLUDE_Dir, Foo_INCLUDE_PATH etc manually, but clearly this is not the right solution. Generally, after spending a couple of days fighting through the various packages to generate a solution by manually setting INCLUDE PATHS, LIBRARY PATHS and other options, I just deal with the solution and don't touch CMake again. But I would love to understand what I'm missing about find_package for my (surely not uncommon) use case of wanting to control my project dependencies rather than just using sudo port install * and installing random versions of projects to my global system folders.
As error message says, CMAKE_PREFIX_PATH should be set to installation prefix of the package. E.g., if the package has been built using CMake, this is CMAKE_INSTALL_PREFIX variable's value, if the package has been build using Autotools, this is value of --prefix option used for configure it, and so on.
CMake doesn't search every directory under CMAKE_PREFIX_PATH. That is why specifying it as /users/foo/src is useless if you have the package installed at /users/foo/src/eigen-install.
Instead, you may install all 3d-party packages into /users/foo/src/install, and use that path as CMAKE_PREFIX_PATH in your main project.