CMake's add_custom_command does not work as advertised - cmake

I cannot, for the life of me, understand why add_custom_command is not working the way it is described in the documentation. I have a json that that I need minimized and converted to a C header that I can include, so I have python script to handle that. The command I have should be dead simple:
add_custom_command(
OUTPUT include/messages.h
COMMAND ${PYTHON_PREFER} ../scripts/json2c.py -i data/messages.json -o include/messages.h -n messages
DEPENDS data/messages.json
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
But as near as I can tell, dependencies simply don't work. I've tried multiple ways to tie this into my main application with the target app.
target_sources(app PRIVATE include/messages.h)
and
add_custom_target(messages_h DEPENDS include/messages.h)
add_dependencies(app messages_h)
do exactly the same thing. (Not using either will never update the file) The header is regenerated every time, so it's not detecting that the input json file hasn't changed. And, the target is only regenerated every OTHER time, so cmake isn't detecting that the header is changing, even though it's the first thing to be updated.
[main] Building folder: CCM
[build] Starting build
[proc] Executing command: C:\Programs\CMake\bin\cmake.EXE --build c:/Users/abram/Workspaces/CCM/build --config Debug --target all --
[build] [1/1 100% :: 0.145] Generating include/messages.h
[build] Build finished with exit code 0
Followed By:
[main] Building folder: CCM
[build] Starting build
[proc] Executing command: C:\Programs\CMake\bin\cmake.EXE --build c:/Users/abram/Workspaces/CCM/build --config Debug --target all --
[build] [1/12 8% :: 0.121] Generating include/messages.h
[build] [2/12 16% :: 0.827] Building CXX object CMakeFiles/app.dir/src/broadcaster.cpp.obj
[build] [3/12 25% :: 0.888] Linking CXX static library app\libapp.a
[build] [4/12 33% :: 1.048] Linking CXX executable zephyr\zephyr_pre0.elf
[build]
[build] [5/12 41% :: 1.266] Generating dev_handles.c
[build] [6/12 50% :: 1.399] Building C object zephyr/CMakeFiles/zephyr_pre1.dir/dev_handles.c.obj
[build] [7/12 58% :: 1.533] Linking CXX executable zephyr\zephyr_pre1.elf
[build]
[build] [8/12 66% :: 1.610] Generating linker.cmd
[build] [9/12 75% :: 1.773] Generating isr_tables.c, isrList.bin
[build] [11/12 83% :: 1.893] Building C object zephyr/CMakeFiles/zephyr_final.dir/isr_tables.c.obj
[build] [11/12 91% :: 1.912] Building C object zephyr/CMakeFiles/zephyr_final.dir/dev_handles.c.obj
[build] [12/12 100% :: 2.279] Linking CXX executable zephyr\zephyr.elf
[build] Memory region Used Size Region Size %age Used
[build] FLASH: 44672 B 512 KB 8.52%
[build] SRAM: 34432 B 128 KB 26.27%
[build] BACKUP_SRAM: 0 GB 4 KB 0.00%
[build] IDT_LIST: 0 GB 2 KB 0.00%
[build] Build finished with exit code 0
Repeat Ad Infinitum
I am very confused since I find it hard to believe that CMake's dependency system simply doesn't work, or that this function doesn't work as intended. But as far as I understand it according to the documentation, this should work. What gives?
I'm gonna try and convert them to a c file instead of a header which I think CMake will be happier about, but I still think this should have worked.
For further context, I'm using CMake 3.24.0-rc4 Ninja 1.11.0, and GCC 11.2.1 for ARM on Windows 11. I'm using Zephyr RTOS as well which has some heavy CMake frameworking. This could be affecting the behavior, but feel like that would be highly unusual.

The OUTPUT argument to add_custom_command is relative to the current binary directory, so you're creating the wrong file.
You need to adjust your paths to keep everything predictably isolated to the binary directory.
Here's a correct example:
cmake_minimum_required(VERSION 3.23)
project(example)
find_package(Python3 REQUIRED)
add_custom_command(
OUTPUT include/messages.h
COMMAND Python3::Interpreter ../scripts/json2c.py -i data/messages.json -o "${CMAKE_CURRENT_BINARY_DIR}/include/messages.h" -n messages
DEPENDS data/messages.json ../scripts/json2c.py
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
VERBATIM
)
add_executable(app "${CMAKE_CURRENT_BINARY_DIR}/include/messages.h")
target_include_directories(app PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/include")
Don't forget to declare a dependency on the script itself.

Related

cmake move build files in a subdirectory after configuring and building [duplicate]

I'm using cmake to compile a C++ project, and I want cmake to generate all the output files(metafiles like Makefile used to create binaries) in the build folder. I've checked all the answers in How do I make cmake output into a 'bin' dir?, none of them worked for me(suprisingly!). Files are generated in the root folder instead of in the build folder, what's wrong here? I guess I must have missed something.
Code Structure
➜ cmake-test tree .
.
├── CMakeLists.txt
└── hello.cpp
0 directories, 2 files
CMakeLists.txt
# Specify the minimum version for CMake
cmake_minimum_required(VERSION 3.11)
# Project's name
project(hello)
# Set the output folder where your program will be created
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
# The following folder will be included
include_directories("${PROJECT_SOURCE_DIR}")
add_executable(hello ${PROJECT_SOURCE_DIR}/hello.cpp)
Build Commands and Outputs
➜ cmake-test cmake .
-- The C compiler identification is GNU 8.2.0
-- The CXX compiler identification is GNU 8.2.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/searene/CLionProjects/cmake-test
➜ cmake-test ls
bin CMakeCache.txt CMakeFiles cmake_install.cmake CMakeLists.txt hello.cpp Makefile
cmake version
➜ cmake-test cmake --version
cmake version 3.11.4
CMake suite maintained and supported by Kitware (kitware.com/cmake).
OS
Linux
The usual way to do this, rather than changing variables to set the path, is simply to create the output directory, change to it, and run cmake from there. So instead of cmake . you usually have cmake .. or similar.
I understand the initial impulse to say "But I expect my build system to write output somewhere else." But CMake is not usually used in the way you were initially expecting, and other people who run your CMake build won't expect what you were expecting, so it's probably best to just use the built-in, default behavior, which is to put the output wherever cmake was run.
Put another way: You are fighting against the tool. Don't do that.
Disclaimer: I recommend going with #john-zwinck's answer.
By default, cmake uses the current working directory as build directory and whatever path you provide as source directory. So the normal way of achieving your goal is
create the build directory (mkdir build)
go there (cd build)
call cmake with the source dir as argument (cmake path/to/source)
BUT there is another way, as far as I know not documented in the cmake docs and only kept for compatibility reasons or internal usage, that some people are using. The -B and -H flags
cmake -Hpath/to/source -Bpath/to/build
or even from the source dir
cmake . -Bbuild
Important: no space after -B.
CMake 3.19.1 (not sure how about older ones) has following option (from docs):
cmake [<options>] -S <path-to-source> -B <path-to-build>
Uses as the build tree and as the
source tree. The specified paths may be absolute or relative to the
current working directory. The source tree must contain a
CMakeLists.txt file. The build tree will be created automatically if
it does not already exist. For example:
cmake -S src -B build

Error with Dockerfile in Rust, x86_64-unknown-linux-musl

I'm creating a Dockerfile for my Rust package, following the example shown here: https://alexbrand.dev/post/how-to-package-rust-applications-into-minimal-docker-containers/
FROM rust:1.47.0 AS build
WORKDIR /usr/src
RUN rustup target add x86_64-unknown-linux-musl
RUN apt-get update
RUN apt-get install cmake musl-tools clang libc++-dev build-essential autoconf libtool pkg-config
# Create a dummy project and build the app's dependencies.
# If the Cargo.toml or Cargo.lock files have not changed,
# we can use the docker build cache and skip these (typically slow) steps.
RUN USER=root cargo new mypackage
WORKDIR /usr/src/mypackage
COPY Cargo.toml build.rs ./
COPY .git ./.git
RUN cargo build --release
# Copy the source and build the application.
COPY src ./src
RUN cargo install --target x86_64-unknown-linux-musl --path .
However, it fails at the step with cargo install, which appears to be because it's unable to find musl-g++. That seems strange.
Am I misunderstanding the error? I'm a bit lost as to how to move forward with this.
Here is the entire message:
Step 12/16 : RUN cargo install --target x86_64-unknown-linux-musl --path .
---> Running in d861b7efa994
...
error: failed to run custom build command for `libmimalloc-sys v0.1.18`
Caused by:
process didn't exit successfully: `/usr/src/mypackage/target/release/build/libmimalloc-sys-9ec3b6c9ac1c8d9d/build-script-build` (exit code: 101)
--- stdout
running: "cmake" "/usr/local/cargo/registry/src/github.com-1ecc6299db9ec823/libmimalloc-sys-0.1.18/c_src/mimalloc" "-DMI_OVERRIDE=OFF" "-DMI_BUILD_TESTS=OFF" "-DMI_SECURE=OFF" "-DMI_LOCAL_DYNAMIC_TLS=OFF" "-Dmi_defines=MI_DEBUG=0" "-DCMAKE_INSTALL_PREFIX=/usr/src/mypackage/target/x86_64-unknown-linux-musl/release/build/libmimalloc-sys-ea7ff527a98597ef/out" "-DCMAKE_C_FLAGS= -ffunction-sections -fdata-sections -fPIC -m64" "-DCMAKE_C_COMPILER=/usr/bin/musl-gcc" "-DCMAKE_CXX_FLAGS= -ffunction-sections -fdata-sections -fPIC -m64" "-DCMAKE_CXX_COMPILER=musl-g++" "-DCMAKE_ASM_FLAGS= -ffunction-sections -fdata-sections -fPIC -m64" "-DCMAKE_ASM_COMPILER=/usr/bin/musl-gcc" "-DCMAKE_BUILD_TYPE=Release"
-- The C compiler identification is GNU 8.3.0
-- The CXX compiler identification is unknown
-- Check for working C compiler: /usr/bin/musl-gcc
-- Check for working C compiler: /usr/bin/musl-gcc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Configuring incomplete, errors occurred!
See also "/usr/src/mypackage/target/x86_64-unknown-linux-musl/release/build/libmimalloc-sys-ea7ff527a98597ef/out/build/CMakeFiles/CMakeOutput.log".
See also "/usr/src/mypackage/target/x86_64-unknown-linux-musl/release/build/libmimalloc-sys-ea7ff527a98597ef/out/build/CMakeFiles/CMakeError.log".
--- stderr
CMake Error at CMakeLists.txt:2 (project):
The CMAKE_CXX_COMPILER:
musl-g++
is not a full path and was not found in the PATH.
Tell CMake where to find the compiler by setting either the environment
variable "CXX" or the CMake cache entry CMAKE_CXX_COMPILER to the full path
to the compiler, or to the compiler name if it is in the PATH.
thread 'main' panicked at '
command did not execute successfully, got: exit code: 1
build script failed, must exit now', /usr/local/cargo/registry/src/github.com-1ecc6299db9ec823/cmake-0.1.45/src/lib.rs:894:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
warning: build failed, waiting for other jobs to finish...
error: failed to compile `mypackage v0.1.0 (/usr/src/mypackage)`, intermediate artifacts can be found at `/usr/src/mypackage/target`
Caused by:
build failed
I would start by running the base image only interactively and look for musl-g++. If not found, add the installation to the Dockerfile and try again.

Cmake not changing build flags

Consider the following simple openMP program:
program hello
use OMP_LIB
implicit none
integer :: nthreads, tid
!$OMP PARALLEL PRIVATE(nthreads, tid)
tid = omp_get_thread_num()
nthreads = omp_get_num_threads()
! print *, "hello"
print *,"Thread:", tid, "of", nthreads
!$OMP END PARALLEL
end program hello
when i compile it as
gfortran -fopenmp hello.90 -o hello.x
I get output as:
Thread: 2 of 4
Thread: 1 of 4
Thread: 0 of 4
Thread: 3 of 4
as expected.
Now if i consider the following CMakeLists.txt file
cmake_minimum_required(VERSION 2.8.9)
project (hello Fortran)
enable_language(Fortran)
IF(NOT CMAKE_BUILD_TYPE)
message("NO BUILD TYPE PROVIDED")
message("DEFAULT BUILD TYPE SET TO 'Release'")
set(CMAKE_BUILD_TYPE 'Release')
ENDIF()
IF(${CMAKE_BUILD_TYPE} MATCHES RELEASE OR ${CMAKE_BUILD_TYPE} MATCHES Release)
message("MAKING RELEASE BUILD")
set(CMAKE_Fortran_FLAGS_RELEASE "-fopenmp")
message("FLAGS: ${CMAKE_Fortran_FLAGS_RELEASE}")
ENDIF()
add_executable(hello.x hello.f90)
Considering above file is right, it should add omp flag to make file and hence compile and run same, however
$ mkdir build; cd build
$ cmake ..
-- The Fortran compiler identification is GNU 6.1.0
-- Checking whether Fortran compiler has -isysroot
-- Checking whether Fortran compiler has -isysroot - yes
-- Checking whether Fortran compiler supports OSX deployment target flag
-- Checking whether Fortran compiler supports OSX deployment target flag - yes
-- Check for working Fortran compiler: /usr/local/bin/gfortran
-- Check for working Fortran compiler: /usr/local/bin/gfortran - works
-- Detecting Fortran compiler ABI info
-- Detecting Fortran compiler ABI info - done
-- Checking whether /usr/local/bin/gfortran supports Fortran 90
-- Checking whether /usr/local/bin/gfortran supports Fortran 90 - yes
NO BUILD TYPE PROVIDED
DEFAULT BUILD TYPE SET TO 'Release'
MAKING RELEASE BUILD
FLAGS: -fopenmp
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/user/Programs/omp/build
$
$ make
Scanning dependencies of target hello.x
[ 50%] Building Fortran object CMakeFiles/hello.x.dir/hello.f90.o
[100%] Linking Fortran executable hello.x
Undefined symbols for architecture x86_64:
"_omp_get_num_threads_", referenced from:
_MAIN__ in hello.f90.o
"_omp_get_thread_num_", referenced from:
_MAIN__ in hello.f90.o
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status
make[2]: *** [hello.x] Error 1
make[1]: *** [CMakeFiles/hello.x.dir/all] Error 2
Which is same as missing -fopenmp flag. How to add it?
The set command for CMAKE_BUILD_TYPE take a "non-string" argument apparently.
Changing
set(CMAKE_BUILD_TYPE 'Release')
to
set(CMAKE_BUILD_TYPE Release)
solved the problem for me. I first dug into the cache system to understand why your setting would not work and there was no reason. I found a CMAKE_Fortran_FLAGS_'Release' entry in ccmake and looked again at the variable CMAKE_BUILD_TYPE in the docs, and it takes values empty, Debug, Release, RelWithDebInfo, MinSizeRel (which I understood as being unquoted).

How do I build/compile Fortran with MinGW gfortran via CMake?

I've got much more I've got to get figured out with CMake than just the following problem, but it's the first and simplest one which I still can't get past. I've scoured the interwebs and even borrowed the 'Mastering CMake' book from a friend, but I'm still having the hardest time... A lot of stuff exists online with regards to CMake, Fortran, and MinGW, and even combinations of two at a time. But all three together seem to be almost non-existent.
All I want to do (at this point) is get a simple Fortran program built and compiling using CMake on Windows, using MinGW's gfortran compiler.
...And I'm a CMake n00b.
This is what I've been working with so far:
CMakeLists.txt:
project(cmake_test Fortran)
add_executable(testf test.f90)
test.f90:
program test
write(*,*)"hello world"
endprogram test
I've got the MSYS2 version of MinGW, since that's the only version that the code I'm eventually going to be compiling will compile with on Windows. (Ie. when I compile it with my own Makefile in the MSYS2 shell, it compiles.)
I've got my Windows Path appended with ;C:\msys64\mingw64\bin. (I've also tried ;C:\msys64\usr\bin, but it complains about sh.exe being in the same directory, among other issues.)
Then I pop open the CMake-GUI, load in the CMakeLists above, hit Configure, specify the generator for the project to be "MinGW Makefiles", select "Use default native compilers", and get the following output:
The Fortran compiler identification is GNU 5.4.0
Check for working Fortran compiler: C:/msys64/mingw64/bin/gfortran.exe
Check for working Fortran compiler: C:/msys64/mingw64/bin/gfortran.exe -- works
Detecting Fortran compiler ABI info
Detecting Fortran compiler ABI info - done
Checking whether C:/msys64/mingw64/bin/gfortran.exe supports Fortran 90
Checking whether C:/msys64/mingw64/bin/gfortran.exe supports Fortran 90 -- yes
Configuring done
Then I click Configure again and get:
Configuring done
Then Generate:
Generating done
In my build directory there is then a Makefile and a number of other files and directories.
I try running make in the MSYS2 shell, and I get this:
myself#COMPUTER MSYS /c/users/myself/desktop/dll_test/with_fortran_cmake/build
$ make
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. All rights reserved.
C:\users\myself\desktop\dll_test\with_fortran_cmake\build>
That last line is a prompt. If I type stuff like make it seems to run it again and it just brings up the prompt again, within the prompt. If I hit Ctrl+C, it kills it and returns to the normal MSYS2 prompt.
So I can't figure out how to actually make it, assuming I'm even doing the CMake part right.
Question: How do I get this example code to build/compile/run given the constraints I've listed?
(What I'd actually rather do, once I get past this part, is get it to work with Visual Studio 13, since I have a C++ project being built with CMake (written mostly by someone else to whom I have limited access for questions and aid) from which I want to be able to call my Fortran. Once I get the Fortran into a library of some sort which is callable by the C++ from Visual Studio, the Fortran can pretty much just be left alone as a pre-built library. I know that editing Fortran from VS is not really much of a possibility, and I'm not interested in doing it.)
Here are the contents of the generated Makefile (note my editor replaced tabs with spaces when I copied it here):
# CMAKE generated file: DO NOT EDIT!
# Generated by "MinGW Makefiles" Generator, CMake Version 3.5
# Default target executed when no arguments are given to make.
default_target: all
.PHONY : default_target
# Allow only one "make -f Makefile2" at a time, but pass parallelism.
.NOTPARALLEL:
#=============================================================================
# Special targets provided by cmake.
# Disable implicit rules so canonical targets will work.
.SUFFIXES:
# Remove some rules from gmake that .SUFFIXES does not remove.
SUFFIXES =
.SUFFIXES: .hpux_make_needs_suffix_list
# Suppress display of executed commands.
$(VERBOSE).SILENT:
# A target that is always out of date.
cmake_force:
.PHONY : cmake_force
#=============================================================================
# Set environment variables for the build.
SHELL = cmd.exe
# The CMake executable.
CMAKE_COMMAND = "C:\Program Files (x86)\CMake\bin\cmake.exe"
# The command to remove a file.
RM = "C:\Program Files (x86)\CMake\bin\cmake.exe" -E remove -f
# Escaping for special characters.
EQUALS = =
# The top-level source directory on which CMake was run.
CMAKE_SOURCE_DIR = C:\Users\myself\Desktop\dll_test\with_fortran_cmake
# The top-level build directory on which CMake was run.
CMAKE_BINARY_DIR = C:\Users\myself\Desktop\dll_test\with_fortran_cmake\build
#=============================================================================
# Targets provided globally by CMake.
# Special rule for the target edit_cache
edit_cache:
#$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake cache editor..."
"C:\Program Files (x86)\CMake\bin\cmake-gui.exe" -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
.PHONY : edit_cache
# Special rule for the target edit_cache
edit_cache/fast: edit_cache
.PHONY : edit_cache/fast
# Special rule for the target rebuild_cache
rebuild_cache:
#$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..."
"C:\Program Files (x86)\CMake\bin\cmake.exe" -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
.PHONY : rebuild_cache
# Special rule for the target rebuild_cache
rebuild_cache/fast: rebuild_cache
.PHONY : rebuild_cache/fast
# The main all target
all: cmake_check_build_system
$(CMAKE_COMMAND) -E cmake_progress_start C:\Users\myself\Desktop\dll_test\with_fortran_cmake\build\CMakeFiles C:\Users\myself\Desktop\dll_test\with_fortran_cmake\build\CMakeFiles\progress.marks
$(MAKE) -f CMakeFiles\Makefile2 all
$(CMAKE_COMMAND) -E cmake_progress_start C:\Users\myself\Desktop\dll_test\with_fortran_cmake\build\CMakeFiles 0
.PHONY : all
# The main clean target
clean:
$(MAKE) -f CMakeFiles\Makefile2 clean
.PHONY : clean
# The main clean target
clean/fast: clean
.PHONY : clean/fast
# Prepare targets for installation.
preinstall: all
$(MAKE) -f CMakeFiles\Makefile2 preinstall
.PHONY : preinstall
# Prepare targets for installation.
preinstall/fast:
$(MAKE) -f CMakeFiles\Makefile2 preinstall
.PHONY : preinstall/fast
# clear depends
depend:
$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles\Makefile.cmake 1
.PHONY : depend
#=============================================================================
# Target rules for targets named testf
# Build rule for target.
testf: cmake_check_build_system
$(MAKE) -f CMakeFiles\Makefile2 testf
.PHONY : testf
# fast build rule for target.
testf/fast:
$(MAKE) -f CMakeFiles\testf.dir\build.make CMakeFiles/testf.dir/build
.PHONY : testf/fast
test.obj: test.f90.obj
.PHONY : test.obj
# target to build an object file
test.f90.obj:
$(MAKE) -f CMakeFiles\testf.dir\build.make CMakeFiles/testf.dir/test.f90.obj
.PHONY : test.f90.obj
test.i: test.f90.i
.PHONY : test.i
# target to preprocess a source file
test.f90.i:
$(MAKE) -f CMakeFiles\testf.dir\build.make CMakeFiles/testf.dir/test.f90.i
.PHONY : test.f90.i
test.s: test.f90.s
.PHONY : test.s
# target to generate assembly for a file
test.f90.s:
$(MAKE) -f CMakeFiles\testf.dir\build.make CMakeFiles/testf.dir/test.f90.s
.PHONY : test.f90.s
# Help Target
help:
#echo The following are some of the valid targets for this Makefile:
#echo ... all (the default if no target is provided)
#echo ... clean
#echo ... depend
#echo ... testf
#echo ... edit_cache
#echo ... rebuild_cache
#echo ... test.obj
#echo ... test.i
#echo ... test.s
.PHONY : help
#=============================================================================
# Special targets to cleanup operation of make.
# Special rule to run CMake to check the build system integrity.
# No rule that depends on this can have commands that come from listfiles
# because they might be regenerated.
cmake_check_build_system:
$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles\Makefile.cmake 0
.PHONY : cmake_check_build_system
Version information:
GNU Fortran (GCC) 5.3.0
Windows 7 Enterprise
Cmake 3.5.2
MSYS2 - I'm not sure how to find the version for this
MinGW - I'm not sure how to find the version for this
I've been through a lot of different pages online during my search, and I didn't bother keeping track of them all, but this one in particular is one I keep coming across because it seems like it's very related from the title, but the actual issue and resolution are totally not:
How can I get a basic Fortran file to compile on Windows/MinGW using CMake?
Here is a quick shell session showing how I was able to build your Fortran program using MSYS2, cmake, make, and gfortran. You should try running the same commands that I did and see if they give different outputs then investigate the reason.
The MSYSTEM variable is especially important; it is determined by what shortcut you click on when starting MSYS2.
$ echo $MSYSTEM
MINGW64
$ which cmake
/mingw64/bin/cmake
$ which gfortran
/mingw64/bin/gfortran
$ which make
/usr/bin/make
$ ls
CMakeLists.txt test.f90
$ cat CMakeLists.txt
project(cmake_test Fortran)
add_executable(testf test.f90)
$ cat test.f90
program test
write(*,*)"hello world"
endprogram test
$ mkdir build && cd build
$ cmake -G"MSYS Makefiles" ..
-- The Fortran compiler identification is GNU 6.2.0
-- Check for working Fortran compiler: D:/msys64/mingw64/bin/gfortran.exe
-- Check for working Fortran compiler: D:/msys64/mingw64/bin/gfortran.exe -- works
-- Detecting Fortran compiler ABI info
-- Detecting Fortran compiler ABI info - done
-- Checking whether D:/msys64/mingw64/bin/gfortran.exe supports Fortran 90
-- Checking whether D:/msys64/mingw64/bin/gfortran.exe supports Fortran 90 -- yes
-- Configuring done
-- Generating done
-- Build files have been written to: C:/Users/david/Documents/scraps/test_fortran/build
$ make
Scanning dependencies of target testf
[ 50%] Building Fortran object CMakeFiles/testf.dir/test.f90.obj
[100%] Linking Fortran executable testf.exe
[100%] Built target testf
$ ./testf.exe
hello world
Edit: There IS a working solution here -- read till the end!
Thanks to David Grayson's comment on the original question, I've found a partial solution. "Partial" because it uses f95 instead of gfortran. I'm posting it because it might work for someone else, and if I'm able to figure out how to get it to work with gfortran, I'll just update it.
Turns out the main issue was a pretty simple mistake: I was using "MinGW Makefiles" instad of "MSYS Makefiles".
When I only changed that, however, I got the following output in the CMake-GUI when I clicked Configure:
CMake Error: CMake was unable to find a build program corresponding to "MSYS Makefiles". CMAKE_MAKE_PROGRAM is not set. You probably need to select a different build tool.
CMake Error: CMake was unable to find a build program corresponding to "MSYS Makefiles". CMAKE_MAKE_PROGRAM is not set. You probably need to select a different build tool.
CMake Error: CMAKE_Fortran_COMPILER not set, after EnableLanguage
CMake Error: CMAKE_AR was not found, please set to archive program. Configuring incomplete, errors occurred!
To fix this, I changed my Windows Path again. I'd been using ;C:\msys64\mingw64\bin, and so I switched it to ;C:\msys64\usr\bin.
This then worked (I clicked Configure a second time, clicked Generate, and then ran make via the MSYS2 terminal in the /build directory), but as you can see in the following output, it used f95 instead of gfortran:
The Fortran compiler identification is GNU 5.3.0
Check for working Fortran compiler: C:/msys64/usr/bin/f95.exe
Check for working Fortran compiler: C:/msys64/usr/bin/f95.exe -- works
Detecting Fortran compiler ABI info
Detecting Fortran compiler ABI info - done
Checking whether C:/msys64/usr/bin/f95.exe supports Fortran 90
Checking whether C:/msys64/usr/bin/f95.exe supports Fortran 90 -- yes
Configuring done
I'm still working to get it to use gfortran, and I'll update this solution if I figure it out.
Edit:
Okay, this is obviously more of a hack and I'm sure that there's a better solution. I renamed C:\msys64\usr\bin\f95.exe to something else (so that MSYS2 wouldn't find it as another Fortran compiler before finding gfortran). I also had to clear CMake's cache and restart it. But now it works:
The Fortran compiler identification is GNU 5.3.0
Check for working Fortran compiler: C:/msys64/usr/bin/gfortran.exe
Check for working Fortran compiler: C:/msys64/usr/bin/gfortran.exe -- works
Detecting Fortran compiler ABI info
Detecting Fortran compiler ABI info - done
Checking whether C:/msys64/usr/bin/gfortran.exe supports Fortran 90
Checking whether C:/msys64/usr/bin/gfortran.exe supports Fortran 90 -- yes
Configuring done
Working on figuring out how to do this the "correct" way.
Edit:
Okay, I'm guessing this is the more proper way to do it, as I assume it essentially does the same thing as setting environment variables on the commandline when calling CMake from there.
In the CMake-GUI, I set everything up as explained before, but before clicking Configure for the first time, I clicked the "Add Entry" button with the little plus symbol. I then set two new Cache Entries -- though only one is really necessary:
Name: CMAKE_Fortran_COMPILER
Type: FILEPATH
Value: C:\msys64\usr\bin\gfortran.exe
I also set the following, but this was only to verify that it was calling gfortran properly, as you'll see in the output below:
Name: CMAKE_VERBOSE_MAKEFILE
Type: BOOL
Value: [True]
Then, running make in the MSYS2 terminal, I got the following:
$ make
"/C/Program Files (x86)/CMake/bin/cmake.exe" -H/C/Users/myself/Desktop/dll_test/with_fortran_cmake -B/C/Users/myself/Desktop/dll_test/with_fortran_cmake/build --check-build-system CMakeFiles/Makefile.cmake 0
"/C/Program Files (x86)/CMake/bin/cmake.exe" -E cmake_progress_start /C/Users/myself/Desktop/dll_test/with_fortran_cmake/build/CMakeFiles /C/Users/myself/Desktop/dll_test/with_fortran_cmake/build/CMakeFiles/progress.marks
make -f CMakeFiles/Makefile2 all
make[1]: Entering directory '/c/Users/myself/Desktop/dll_test/with_fortran_cmake/build'
make -f CMakeFiles/testf.dir/build.make CMakeFiles/testf.dir/depend
make[2]: Entering directory '/c/Users/myself/Desktop/dll_test/with_fortran_cmake/build'
"/C/Program Files (x86)/CMake/bin/cmake.exe" -E cmake_depends "MSYS Makefiles" /C/Users/myself/Desktop/dll_test/with_fortran_cmake /C/Users/myself/Desktop/dll_test/with_fortran_cmake /C/Users/myself/Desktop/dll_test/with_fortran_cmake/build /C/Users/myself/Desktop/dll_test/with_fortran_cmake/build /C/Users/myself/Desktop/dll_test/with_fortran_cmake/build/CMakeFiles/testf.dir/DependInfo.cmake --color=
Scanning dependencies of target testf
make[2]: Leaving directory '/c/Users/myself/Desktop/dll_test/with_fortran_cmake/build'
make -f CMakeFiles/testf.dir/build.make CMakeFiles/testf.dir/requires
make[2]: Entering directory '/c/Users/myself/Desktop/dll_test/with_fortran_cmake/build'
make[2]: Nothing to be done for 'CMakeFiles/testf.dir/requires'.
make[2]: Leaving directory '/c/Users/myself/Desktop/dll_test/with_fortran_cmake/build'
make -f CMakeFiles/testf.dir/build.make CMakeFiles/testf.dir/build
make[2]: Entering directory '/c/Users/myself/Desktop/dll_test/with_fortran_cmake/build'
[ 50%] Building Fortran object CMakeFiles/testf.dir/test.f90.obj
/C/msys64/usr/bin/gfortran.exe -c /C/Users/myself/Desktop/dll_test/with_fortran_cmake/test.f90 -o CMakeFiles/testf.dir/test.f90.obj
[100%] Linking Fortran executable testf.exe
"/C/Program Files (x86)/CMake/bin/cmake.exe" -E remove -f CMakeFiles/testf.dir/objects.a
/C/msys64/usr/bin/ar.exe cr CMakeFiles/testf.dir/objects.a #CMakeFiles/testf.dir/objects1.rsp
/C/msys64/usr/bin/gfortran.exe -Wl,--whole-archive CMakeFiles/testf.dir/objects.a -Wl,--no-whole-archive -o testf.exe -Wl,--out-implib,libtestf.dll.a -Wl,--major-image-version,0,--minor-image-version,0
make[2]: Leaving directory '/c/Users/myself/Desktop/dll_test/with_fortran_cmake/build'
[100%] Built target testf
make[1]: Leaving directory '/c/Users/myself/Desktop/dll_test/with_fortran_cmake/build'
"/C/Program Files (x86)/CMake/bin/cmake.exe" -E cmake_progress_start /C/Users/myself/Desktop/dll_test/with_fortran_cmake/build/CMakeFiles 0
And the resulting program works both via the MSYS2 terminal and a Windows command prompt.
...Now I need to figure out how to get this all together with C++ in Visual Studio. Stay tuned for more SO questions! :D

cmake check existence of compiler

I'm trying to play around with cmake to build a small C++-code.
I do not have yet g++
(I'm testing on a virtualbox OS)
When I call cmake .
I get the nasty error messages.
-- The C compiler identification is GNU 4.7.2
**-- The CXX compiler identification is unknown**
-- Check for working C compiler: /usr/bin/gcc
-- Check for working C compiler: /usr/bin/gcc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
**CMake Error: your CXX compiler: "CMAKE_CXX_COMPILER-NOTFOUND" was not found. Please set CMAKE_CXX_COMPILER to a valid compiler path or name.
-- Configuring incomplete, errors occurred!**
Basically, this is OK. It says errors occurred, but it says too much than needed. I just want to get a precise and concise message saying "g++ ist not installed. INSTALL it please".
Is there a way to first check if g++ is installed and then give an appropriate message?
The output you gave shows that CMake attempting to be helpful to you. If it is too verbose for your taste, perhaps the simplest way to reduce it would be to capture it into a variable, then examine it.
You can save the sample CMake script below as detect_cxx_compiler.cmake, and invoke the script using cmake -P detect_cxx_compiler.cmake. The code is written in a manner intended to be helpful to CMake beginners, not for small size or processing efficiency.
cmake_minimum_required(VERSION 2.8.5 FATAL_ERROR)
cmake_policy(VERSION 2.8.5)
# This cmake script (when saved as detect_cxx_compiler.cmake) is invoked by:
#
# cmake -P detect_cxx_compiler.cmake
#
# It is written for clarity, not brevity.
# First make a new directory, so that we don't mess up the current one.
execute_process(
COMMAND ${CMAKE_COMMAND} -E make_directory detection_area
WORKING_DIRECTORY .
)
# Here, we generate a key file that CMake needs.
execute_process(
COMMAND ${CMAKE_COMMAND} -E touch CMakeLists.txt
WORKING_DIRECTORY detection_area
)
# Have CMake check the basic configuration. The output is
# actually in the form that you posted in your question, but
# instead of displaying it onscreen, we save it to a variable
# so that we can select only parts of it to print later.
execute_process(
COMMAND ${CMAKE_COMMAND} --check-system-vars
OUTPUT_VARIABLE the_output
OUTPUT_STRIP_TRAILING_WHITESPACE
WORKING_DIRECTORY detection_area
)
# Eliminate the directory, including all of the files within it that
# CMake created.
execute_process(
COMMAND ${CMAKE_COMMAND} -E remove_directory detection_area
WORKING_DIRECTORY .
)
# Here, you have the entire message captured as a variable.
# Uncomment this next line to convince yourself of this.
#message(STATUS "the_output = |${the_output}|.")
# Here, we search the message to see if the C++ compiler was found or not,
# and print an arbitrary message accordingly.
string(FIND "${the_output}" "CMAKE_CXX_COMPILER-NOTFOUND" scan_result)
#message(STATUS "scan_result = |${scan_result}|.")
if(NOT(-1 EQUAL "${scan_result}"))
message(FATAL_ERROR "A C++ compiler was not detected.")
endif()
message(STATUS "A C++ compiler was detected.")
You should use GCC (Gnu Compiler Collection) frontend. You should install gcc-c++ or something similar package.