CMAKE way to search for .exe file in the CLists text? - cmake

Say I have
set(CMAKE_CXX_COMPILER={$myCompilersEnvVariableName}
and it's not configured
is there an if statement that I can place here something like
if CMAKE_CXX_COMPILER FALSE
search for cl.exe
set(CMAKE_CXX_COMPILER path/to/cl.exe
break
It is not a problem but a theoretical question

Related

Get build command or all compiler flags that will be used to build a target

Is there a sensible way to get a CMake variable containing the build command or all the compiler flags that CMake will associate with a target?
It doesn't seem practical to try to gather and maintain a list of all properties that could add flags. Besides, CMake must have this info somewhere, since it has to eventually generate a build system.
From the CMake docs it looks like this feature once existed and was provided by calling build_command() but this was replaced:
Note In CMake versions prior to 3.0 this command returned a command
line that directly invokes the native build tool for the current
generator.
Is there a new command that gives the old behavior of build_command()?
Is there a sensible way to get a CMake variable containing the build command or all the compiler flags that CMake will associate with a target?
The answer is no (CMake 3.23 is latest at time of writing), not during the CMake configure step.
In general, such a thing is ill-defined, which is likely why it was removed from CMake and will likely not be re-added. The complications arising from generator expressions, multi-config generators, generators that don't construct command lines (like VS/msbuild), source-file-specific properties, and the simple fact that after the command is called, relevant state might change, all make such efforts quixotic.
Honestly, this is such an odd thing to want at configure time, I wonder if this isn't an XY problem. It's unlikely that one target depends on another in such a way that the entire eventual command line is needed (rather than a particular property) to create it.
I know this is many years later now, but what were you trying to do?
CMake provides many ways post-generation to get information about the compiler command lines.
There's the CMake File API, meant for IDE integration,
The CMAKE_EXPORT_COMPILE_COMMANDS option that creates a Clang-compatible compile_commands.json, and then there's
The CMAKE_<LANG>_COMPILER_LAUNCHER variables that would let you instrument a full command line with a custom script while the build is running.
One of these might be useful. The latter is commonly used with ccache, but can be (ab)used with any arbitrary program as long as the output file is eventually generated.
Note that the latter two only work with the Makefile and Ninja generators.
If you want the final output of how the source files will actually be compiled you will want to look at the generated files. I don't really know a better way currently:
Example:
Here is an example output from Ninja Multi
build\CMakeFiles\impl-Release.ninja
This file will list all of the compile definitions, compiler flags, include directories, object directory, etc.
Under the path "cmake-build-debug/CMakeFiles/" you'll find a folder named as "TopFolderOfYourProject.dir", where the cmake generates all its build system files, including a file "build.make". In this file you can see something like this:
CMakeFiles/somepath/somesourcefile.c
#$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=xxx\cmake-build-debug\CMakeFiles --progress-num=$(CMAKE_PROGRESS_1) "Building C object CMakeFiles/somepath/somesourcefile.c.obj"
Besides this, you can find extra info about the flags in the file "flags.make", it contains all extra compiler flags specified by developers.
And in "includes_C.rsp/includes_CXX.rsp" you can see the including path.
Build flags are, actually, associated with source files, because you can have differrent flags for different files. On the other hand, for the most cases these flags are equivalent.
Anyways, to get all build flags for a source file you can use COMPILE_FLAGS property:
get_source_file_property(RESULT file.cpp COMPILE_FLAGS)

Cmake library prefix/suffix

I need to link with a third-party pre-built shared library. On Windows, that means linking with Third_party.lib, and on Linux/Android, that means linking with libThird_party.so. So in the interest of cross-platformness, I tried to write that as:
${CMAKE_IMPORT_LIBRARY_PREFIX}Third_party${CMAKE_IMPORT_LIBRARY_SUFFIX}
Which works fine on Windows, but on Linux/Android, these variables are blank. I get that Linux/Android doesn't have import libraries, but nonetheless these variables being blank is actually a big nuisance. And changing the variables to CMAKE_SHARED_LIBRARY_... doesn't work either, because even though Linux/Android would then look for lib/.so like I want, Windows will look for .dll, which I don't want.
It seems like I can fix this by populating the import library variables (only on Linux) with values from the shared library variables. But... is this really the best way? I can't possibly be the first person to bump into this.
Usually you let CMake and its helpers do that job of figuring the right name out. Quite possibly, for your third party library, there's already a Find<Library>.cmake script out there.
If there isn't: Here's something taken from FindUSB.cmake from GNU Radio
if(NOT LIBUSB_FOUND)
pkg_check_modules (LIBUSB_PKG libusb-1.0)
find_path(LIBUSB_INCLUDE_DIR NAMES libusb.h
PATHS
${LIBUSB_PKG_INCLUDE_DIRS}
/usr/include/libusb-1.0
/usr/include
/usr/local/include
)
find_library(LIBUSB_LIBRARIES NAMES usb-1.0 usb
PATHS
${LIBUSB_PKG_LIBRARY_DIRS}
/usr/lib
/usr/local/lib
)
if(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)
set(LIBUSB_FOUND TRUE CACHE INTERNAL "libusb-1.0 found")
message(STATUS "Found libusb-1.0: ${LIBUSB_INCLUDE_DIR}, ${LIBUSB_LIBRARIES}")
else(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)
set(LIBUSB_FOUND FALSE CACHE INTERNAL "libusb-1.0 found")
message(STATUS "libusb-1.0 not found.")
endif(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)
mark_as_advanced(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARIES)
endif(NOT LIBUSB_FOUND)
Notice the pkg_check_modules directive and the find_library directive that take care of giving you the right things without you hand-appending suffixes etc.
You'll probably want to add the path you expect your .dll to be to the PATHS arguments of find_path and find_library (those are pointers for CMake to know where to look).

cmake add_subdirectory with other cmake filename than CMakeLists.txt

CMake documentation states that when add_subdirectory is executed cmake looks for CMakeLists.txt in the directory. Is there any way to change the name of makefile? For example, if I have two cmake files for two completely different configurations and don't want to mix everything in one.
Of course I can create CMakeLists.txt and include something else in it depending on configuration, but I'm just curious if it's possible to make add_subdirectory look for make file with arbitrary name
No, there is no way to do that. The file name CMakeLists.txt is unconfigurably hard-coded in CMake itself. Your best option is, as you say, create a "signpost" CMakeLists.txt file which will just include() the real content based on whatever logic you need.
I know this question is old but I'll answer anyway in case it helps someone. Per the book "Professional CMake" 3rd edition, you should use
include(fileName [OPTIONAL] [RESULT_VARIABLE myVar] [NO_POLICY_SCOPE])
"include() expects the name of a file to read in, whereas add_subdirectory() expects a directory and will look for a CMakeLists.txt file within that directory. The file name passed to include() typically has the extension .cmake, but it can be anything." pg 56.
There are other differences between add_subdirectory() and include() to be mindful of so I would suggest getting the book and giving it a read.

CMake Fortran compiler-dependent flags

I'm using CMake for a moderate-sized Fortran project; sometimes I build it with gfortran, other times with ifort. When I want to do a debug build, the compiler flags are different; I'd like to have CMake automatically check which compiler is being used and set the flags accordingly.
It looks like this answer shows how to do the same thing for different C++ compilers. There's an example of how to check compilers with Fortran, using
if (Fortran_COMPILER_NAME MATCHES "gfortran.*")
However, this fails to invoke the conditional, because CMake has decided to use f95. Of course, f95 happens to alias to gfortran, but CMake doesn't detect that.
What's the right way to do this?
You can use also use CMAKE_Fortran_COMPILER_ID:
if ("${CMAKE_Fortran_COMPILER_ID}" MATCHES "Intel")
# something
elseif("${CMAKE_Fortran_COMPILER_ID}" MATCHES "GNU")
# something else
endif
Best way is to read file CMakeDetermineFortranCompiler.cmake and related files referenced from it.
Rather than trying to special case for different compilers you should actually test that your compiler supports the flags you want to set using check_fortran_compiler_flag like so:
include(CheckFortranCompilerFlag)
check_fortran_compiler_flag("-my-flag" _my_flag)
if(_my_flag)
set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -my-flag")
endif()
This is both safer and (I think) simpler because you don't need the implied knowledge of which compiler (and version) supports which flag.
It's simple. Only indicate the full path of compiler installed e.g.gfortran. the code: cmake -DCMAKE_fortran_PATH=/usr/bin/gfortran

CMake and clang_complete

I'm wanting to setup my CMakeLists.txt file so that it can generate the .clang_complete file required by the vim plugin clang_complete.
Ordinarily, you would do this by passing a parameter to the python script it supplies with the compiler and all of the parameters for compilation. Note that I am omitting the actual directory cc_args.py is in to save on space.
cc_args.py gcc test.c -o test -I~/IncludeDirs/
You can also do this during the make phase...
make CC='cc_args.py gcc' CXX='cc_args.py g++'
However, I am unsure of how to (if it is possible to) set this up within a CMakeLists.txt file. It's really annoying to have to type this in every time I want to setup clang_complete. The reason why I want to do it this way, is because I have multiple projects that I use a custom script to build the CMakeLists.txt file, so having to write a script for each one or manually place a generic one is a step I'd like to avoid.
I've tried a couple of things that have so far have come up with errors.
I've tried setting CMAKE_CC_COMPILER and CMAKE_CXX_COMPILER to lines similar to the first i.e. "cc_args.py g++". The errors that come up here say that It can't find the compiler (which is understandable).
The next thing I tried was setting the Compiler variables just to the cc_args.py and adding a flag for the actual compiler: suffice to say, that failed horribly. CMake said that it couldn't compile a test program (considering the script isn't a compiler, and the tests don't use the flags I set, I'm not surprised at this).
So without writing any other external scripts that require moving around, is there anyone that can think of a way that can do this?
The solution is to set the CXX environment variable before executing cmake. Something like that:
CXX="$HOME/.vim/bin/cc_args.py clang++" cmake ..
make
See http://www.guyrutenberg.com/2013/01/29/vim-creating-clang_complete-using-cmake/ for more details.
I know you said "without writing any other external scripts," but it seems like you just need a one-liner:
exec cc_args.py g++
And then set that file as your CMAKE_CXX_COMPILER. You could even use CMake's file() function to write the one-liner at build time if you don't want to have to distribute it.