How to check for internet connection with CMake? (automatically prevent fails if there is non) - cmake

For example, when using the ExternalProject or FetchContent module additional data can be downloaded and used within CMake. If there is no internet connection these modules fail and CMake does not finish configuration no matter if downloading was done successful once. There are flags like FETCHCONTENT_FULLY_DISCONNECTED or FETCHCONTENT_UPDATES_DISCONNECTED to prevent checks and therefore prevent failing. But these have to be set manually. (related question: cmake: external project update and a work offline).
Is it possible to check if there is a connection to afterwards set FETCHCONTENT_FULLY_DISCONNECTED automatically? How to do that? Or are there alternative ways to prevent failing of CMake if there is no internet connection?
In our case we are downloading libraries with FetchContent and than use for example find_package to make them available. Our workflow does currently not include manual adjusting of CMake Options/Variables and we do not want to add that. CMake gets all needed options by the IDEs we use, e.g. CMAKE_BUILD_TYPE or custom flags. We would need to double the targets to have a non-connection version for each existing combination. Therefore this semi-manual approach is also not feasible.

I found a workaround to check for a connection. Although it will not work all the time its good enough for us. I'ts based on CMake's execute_process and the questions https://stackoverflow.com/a/27590444/9909548, https://stackoverflow.com/a/6357629/9909548 and https://superuser.com/q/1406089.
execute_process(
COMMAND ping www.google.com -n 2 -w 1000
RESULT_VARIABLE NO_CONNECTION
)
if(NO_CONNECTION GREATER 0)
set(FETCHCONTENT_FULLY_DISCONNECTED ON)
else()
set(FETCHCONTENT_FULLY_DISCONNECTED OFF)
endif()
Hope its correct to add this as an answer although I will not accept it, rather than adding it to the question as a research result.

Modified answer that works with recent cmake and more platforms:
if(MSVC)
execute_process(
COMMAND ping www.google.com -n 2
ERROR_QUIET
RESULT_VARIABLE NO_CONNECTION
)
else()
execute_process(
COMMAND ping www.google.com -c 2
ERROR_QUIET
RESULT_VARIABLE NO_CONNECTION
)
endif()
if(NOT NO_CONNECTION EQUAL 0)
set(FETCHCONTENT_FULLY_DISCONNECTED ON)
message(WARNING "Fetch offline mode: requires already populated _deps")
else()
set(FETCHCONTENT_FULLY_DISCONNECTED OFF)
endif()

Related

build yaml-cpp lib with -m32 (32-bit) - on linux /w gcc or llvm

subject pretty much says it all:
I downloaded yaml-cpp version 0.6.3.
I need to compile on linux x86_64, target linux x86_32 (build on 64 bit, use result on 32-bit)
I have been trying to add a new "YAML_BUILD_32BIT" option - similar to the existing YAML_BUILD_SHARED_LIBS option.
When I detect YAML_BUILD_32BIT is set: I try to add "-m32" to a bunch of cmake variables.
My problem is that this list of variables seems endless or not well defined.
"yaml_cxx_flags" are passed to the compile and link steps for the yaml-cpp library code...but not to build the google 'mock' code. Similarly, I found other variables that I can also set, so that google-mock is compiled with -m32 as well...but then the yaml-cpp mock tests do not see the flag...and so on and so on.
I think I am missing something very fundamental. I expect that there will be a single variable I need to update...maybe 2 or 3. I don't expect to keep finding more and more.
--
Adding more specifics:
To CMakeLists.txt:
added line (immediately after the similar line which creates the YAML_BUILD_SHARED_LIBS flag)
option(YAML_BUILD_32BIT "Build with '-m32'" OFF)
then a bit later (immediately after the YAML_BUILD_SHARED_LIBS if/else):
if(YAML_BUILD_32BIT)
# seem to need this one for the shared lib link of yaml-cpp lib
# CXX_FLAGS passed to both compile and link
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32")
# seem to need this one, to get flag passed to gmock build
set(FLAG_TESTED "${FLAG_TESTED} -m32")
# this one passed to compile and link of testcase
set(yaml_cxx_flags "${yaml_cxx_flags} -m32")
endif()
and made "FLAG_TESTED" addive, on immediately following line:
set(FLAG_TESTED "-Wextra -Wshadow -Weffc++ -pedantic -pedantic-errors ${FLAG_TESTED}")
Given the above, then configuring with:
# using cmake/3.19.3
cmake -G "Unix Makefiles" -DYAML_BUILD_SHARED_LIBS=ON -DYAML_BUILD_32BIT=ON"
... and then building with 'make VERBOSE=1', I see that 'gmock-all.cc.o' did not receive the -m32 flag. (gmock-all.cc.o is only the first such file in my log..there are others.)
If I remove other of the lines in my CMakeLists.txt which attempted to add flags - then other compile commands or other link commands don't see -m32 and will fail.
As I said: I think there is something fundamental that I have misunderstood. I suspect that it is much easier to configure a 32-bit build than I am making it.
With some help from a coworker, I ended up doing the following:
top-level CMakeLists.txt file (near line 28, immediately following definition of YAML_BUILD_SHARED_LIBS variable):
option(YAML_BUILD_32BIT "Build with '-m32'" OFF)
if(YAML_BUILD_32BIT)
add_compile_options(-m32)
add_link_options(-m32)
endif()
in .../test/CMakeLists.txt (near line 10):
if(YAML_BUILD_32BIT)
set(GTEST_EXTRA_FLAGS "-DCMAKE_CXX_FLAGS=-m32")
endif()
then add new flag to "ExternalProject_Add(..." call (near line .../test/CMakeLists.txt:22):
ExternalProject_Add(
googletest_project
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/gtest-1.8.0"
INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/prefix"
CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
-DBUILD_GMOCK=ON
-Dgtest_force_shared_crt=ON
${GTEST_EXTRA_FLAGS} # <- this line added
)
The above has the effect of passing the extra "-m32" flag the embedded gmocktest project.
Given the above changes, the cmake command line above generates something that will build successfully (at least on RHEL-7, with gcc/5.2.0)
Hope this can help somebody else.
Henry

GBenchmark and CMake

From relevant search on the web, I got an impression that
google-benchmark is not easily incorporated into a CMake-project.
One way I could do that is adding as external project,
replicating verbatim the corresponding text for GTest in google-test's readme:
# adding google-benchmark as external git project
#=======================================================
configure_file(extern/googlebenchmark/CMakeLists.txt.in googlebenchmark-download/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googlebenchmark-download)
if(result)
message(FATAL_ERROR "CMake step for googlebenchmark failed: ${result}")
endif()
execute_process(COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googlebenchmark-download )
if(result)
message(FATAL_ERROR "Build step for googlebenchmark failed: ${result}")
endif()
# Prevent overriding the parent project's compiler/linker
# settings on Windows
set(gbenchmark_force_shared_crt ON CACHE BOOL "" FORCE)
add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googlebenchmark-src
${CMAKE_CURRENT_BINARY_DIR}/googlebenchmark-build
EXCLUDE_FROM_ALL)
if (CMAKE_VERSION VERSION_LESS 2.8.11)
include_directories("${gbenchmark_SOURCE_DIR}/include")
endif()
and having CMakeLists.txt.in with the contents as in
How to build and link google benchmark using cmake in windows
This however has a huge downside: every time we change something in the CMakeLists.txt -- the topmost one -- that hosts all this, it starts building google-benchmark from scratch,
and running all the "tests", whatever they are. Thus compilation times become longer.
Without a root access to a Linux server, is there any more-less portable way
of having the benchmark code installed in one's home directory, while being
able to link towards it in a CMake-project?
EDIT: I must say I've been able to git clone the benchmark code and successfully built it in my home directory.
EDIT: Answering my own question. I am not sure if this warrants a close, and leave it to the patrons to decide, but I've solved the problem as follows. In the CMakeLists.txt one can have the following contents:
cmake_minimum_required(VERSION 3.15)
set(CMAKE_CXX_STANDARD 17)
add_executable(sample_bench sample_bench.cpp)
target_link_libraries(sample_bench PUBLIC benchmark benchmark_main pthread)
target_link_directories(sample_bench PUBLIC ~/local/benchmark/build/src)
target_include_directories(sample_bench PUBLIC
~/local/benchmark/include)
The key here is target_link_directories, which is specified with -L in the example in https://github.com/google/benchmark
Answering my own question. I've solved the problem as follows. In the CMakeLists.txt one can have the following contents:
cmake_minimum_required(VERSION 3.15)
set(CMAKE_CXX_STANDARD 17)
add_executable(sample_bench sample_bench.cpp)
target_link_libraries(sample_bench PUBLIC benchmark benchmark_main pthread)
target_link_directories(sample_bench PUBLIC ~/local/benchmark/build/src)
target_include_directories(sample_bench PUBLIC
~/local/benchmark/include)
The key here is target_link_directories, which is specified with -L in the example in https://github.com/google/benchmark
This is enough to run the sample benchmark, at least -- haven't tried others.
That is, once you have built benchmark somewhere -- even in your home directory, as in the example -- you can point CMake to the designated locations,
in order for your code to compile.

CMake call add_subdirectory within custom command

I'm working with a code generator that produces C++ and a CMakeLists.txt file, unfortunately I cannot use this in my main CMakeLists.txt file for testing purposes.
For example you have the following CMakeLists.txt file:
project(SomeProject CXX C)
add_custom_command(OUTPUT ${SRCS}
COMMAND ${CODEGEN_CLI_PATH} -i "${INPUT}" -o "${OUT}"
COMMENT "Generating sources"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
VERBATIM
)
add_custom_target(CODEGEN
DEPENDS
${SRCS}
)
# Needs to be executed after the custom command
add_subdirectory(${GENERATED_CMAKE_LISTS_LOCATION})
Is it possible to use functions such as add_subdirectory only after you execute custom commands for a particular target, such as CODEGEN?
I've already tried to execute it by adding an extra line to the existing custom command:
COMMAND ${CMAKE_COMMAND} -D DIR=${GENERATED_CMAKE_LISTS_LOCATION} -P add_subdirectories.cmake
Unfortuantly this doesn't work because it isn't allowed to execute functions like add_subdirectory in script mode.
Neither I can manage to call custom made functions (that are executing add_subdirectory) from add_custom_command that are located in the same file.
Nope, it is not possible. The add_subdirectory command is run during configuration step, while CODEGEN is a target that runs during build.
You seem to be doing something wrong, so the only advice I can give you is to use execute_process command to run commands you need. The execute_process command is executed during configuration stage, so it will be able to generate files you need before add_subdirectory.
But again, please describe your problem, why do you want CMake to do that.
I have a huge fixed unsigned char array that I compiled into a static library. The way I work around it is by:
if(NOT EXISTS ${PATH_TO_FOLDER}/smeagol.a)
add_subdirectory(smeagol)
endif()
I'm still looking for a nicer kung-fu way to do it using cmake. I feel that its out there, and I will update this answer once i find it.

Silence custom command depending on CMAKE_VERBOSE_MAKEFILE

I've a custom command in my CMake script which generates a lot of output. I'd like to take advantage of CMAKE_VERBOSE_MAKEFILE so I can decide if I want to see this output or not.
Is there a common way for doing this?
The one way I see is to redirect output to /dev/null depending on this CMake's flag, but what about Windows and other OSes?
Is there a portable or recommended way? What about default rules for C/C++ compiling commands?
Technically speaking, CMAKE_VERBOSE_MAKEFILE exists for the purpose of hiding and showing command lines, not command output.
If I had to do this, I would use a custom variable.
But on the main topic, here is how you should do:
if (COMMAND_VERBOSE)
execute_process(COMMAND "mycustom_command")
else (COMMAND_VERBOSE)
execute_process(COMMAND "mycustom_command" OUTPUT_QUIET)
endif (COMMAND_VERBOSE)
This is the most portable way to do so.
There is also an ERROR_QUIET flag, however it is a bad idea to disable error messages, else the user would be unable to see why the command failed if it failed.
If you are using add_custom_command or add_custom_target instead, such a flag does not exist.
You'll have to provide a manual redirection to /dev/null (Unix), or NUL (Windows).
As SirDarius pointed out, execute_process() has an option to silence tool output, while add_custom_command() / add_custom_target() do not.
But there is a way to work around this: By putting the actual call to your tool in a separate CMake script wrapper, using execute_process() with OUTPUT_QUIET enabled or disabled depending on a switch:
# mycustom_command.cmake
if ( OUTPUT )
execute_process( COMMAND mycustom_command )
else()
execute_process( COMMAND mycustom_command OUTPUT_QUIET )
endif()
Then, use add_custom_command() and the CMake script processing mode (-P) to call that script from your main CMakeLists.txt, with the script switch enabled / disabled by whatever variable you use for that purpose in your CMakeLists.txt file.
add_custom_command( OUTPUT outfile
COMMAND ${CMAKE_COMMAND} -P mycustom_command.cmake -DOUTPUT=${OUTPUT_DESIRED}
)
This is fully portable. If your mycustom_command is build from within your project as a target, just add it as DEPENDENCY to your add_custom_command() to have it build in time for the script call.

Run Command after generation step in CMake

I have a command line tool that should be run after CMake created my .sln-file. Is there any way to do that using CMake?
Using execute_process(COMMAND ..) at the end of the CMakeLists.txt does not help because this is executed after the Configure step, however, the .sln-file is created in the generation step.
Thanks a lot!
A rather horrifying way to do it is by calling cmake from cmake and doing the post-generate stuff on the way out of the parent script.
option(RECURSIVE_GENERATE "Recursive call to cmake" OFF)
if(NOT RECURSIVE_GENERATE)
message(STATUS "Recursive generate started")
execute_process(COMMAND ${CMAKE_COMMAND}
-G "${CMAKE_GENERATOR}"
-T "${CMAKE_GENERATOR_TOOLSET}"
-A "${CMAKE_GENERATOR_PLATFORM}"
-DRECURSIVE_GENERATE:BOOL=ON
${CMAKE_SOURCE_DIR})
message(STATUS "Recursive generate done")
# your post-generate steps here
# exit without doing anything else, since it already happened
return()
endif()
# The rest of the script is only processed by the executed cmake, as it
# sees RECURSIVE_GENERATE true
# all your normal configuration, targets, etc go here
This method doesn't work well if you need to invoke cmake with various combinations of command line options like "-DTHIS -DTHAT", but is probably acceptable for many projects. It works fine with the persistently cached variables, including all the cmake compiler detection when they're initially generated.
From the following links, it seems like there is no such command to specify execution after CMake generated .sln files.
https://cmake.org/pipermail/cmake/2010-May/037128.html
https://cmake.org/pipermail/cmake/2013-April/054317.html
https://cmake.org/Bug/view.php?id=15725
An alternative is to write a wrapper script as described in one of the above links.
cmake ..
DoWhatYouWant.exe
Yes, add_custom_command paired with add_custom_target got this covered
http://cmake.org/cmake/help/cmake-2-8-docs.html#command:add_custom_command
http://cmake.org/cmake/help/cmake-2-8-docs.html#command:add_custom_target
For an example take a look at my answer to another question
cmake add_custom_command