How to cross-compile Clang on Ubuntu for Win32? - cmake

I downloaded & extracted:
http://releases.llvm.org/5.0.1/llvm-5.0.1.src.tar.xz
http://releases.llvm.org/5.0.1/cfe-5.0.1.src.tar.xz
Then:
$ mv cfe-5.0.1.src llvm-5.0.1.src/tool/clang
Created the following llvm-5.0.1.src/mingw_cross_toolchain.cmake file:
set(CMAKE_SYSTEM_NAME Windows)
set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)
# cross compilers to use for C and C++
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc-posix)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++-posix)
set(CMAKE_Fortran_COMPILER ${TOOLCHAIN_PREFIX}-gfortran)
set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
# target environment on the build host system
# set 1st to dir with the cross compiler's C/C++ headers/libs
set(CMAKE_FIND_ROOT_PATH /usr/lib/gcc/${TOOLCHAIN_PREFIX}/7.3-posix)
# modify default behavior of FIND_XXX() commands to
# search for headers/libs in the target environment and
# search for programs in the build host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
Then:
$ cd llvm-5.0.1.src
$ mkdir build
# cd build
$ cmake -D CMAKE_TOOLCHAIN_FILE=../mingw_cross_toolchain.cmake
Then in the following build/NATIVE/include/llvm/Config/llvm-config.h I have:
/* Define if this is Unixish platform */
#define LLVM_ON_UNIX 1
/* Define if this is Win32ish platform */
/* #undef LLVM_ON_WIN32 */
Which will make the build fail. Since LLVM_ON_WIN32 depends on the WIN32 flag, I tried to define that flag on the command line and in the mingw_cross_toolchain.cmake but alas with no effect on the generated build/NATIVE/include/llvm/Config/llvm-config.h.
How can we define that WIN32 flag properly?

Ok so I need to force by setting the flags in cmake/modules/HandleLLVMOptions.cmake to:
set(WIN32 1)
set(UNIX 0)
Then I need to be able to execute the future intermediate Win32 executables:
$ sudo apt-get install wine-binfmt
$ sudo update-binfmts --import /usr/share/binfmts/wine
After that I need to set the WINEPATH to find the DLLs:
$ export WINEPATH="/usr/x86_64-w64-mingw32/lib/;/usr/lib/gcc/x86_64-w64-mingw32/7.3-posix"
Now I'll be able to cross-compile everything properly!

Related

Configure cmake to work with homebrew libraries instead system-provided libraries

I find myself going against the grain configuring cmake paths with ccmake over and over again as with every change of for ex. compiler some of my library paths get lost.
In particular paths to (unlinked) lapack, lapacke, gsl get either lost or set to system defaults instead the ones I've installed with brew.
There has to be a way to tell cmake to "ignore" system libraries and instead look in homebrew paths (say. /opt/homebrew/lib, /opt/homebrew/include etc.).
I'd prefer not to link those libraries as this is not recommend and I'm not experienced in switching environments.
[EDIT] MRE:
git clone https://gitlab.physik.uni-muenchen.de/AG-Scrinzi/tRecX.git
cd tRecX
cmake . -DCMAKE_BUILD_TYPE=Parallel
make -j 8
I add the following to .bash_profile/.zshrc:
export LDFLAGS="-L/opt/homebrew/opt/lapack/lib -L/opt/homebrew/opt/lapack/lib"
export CPPFLAGS="-I/opt/homebrew/opt/lapack/include -I/opt/homebrew/opt/openblas/include"
export PKG_CONFIG_PATH="/opt/homebrew/opt/lapack/lib/pkgconfig /opt/homebrew/opt/openblas/lib/pkgconfig"
then I try:
cmake . -DCMAKE_PREFIX_PATH=/opt/homebrew -DCMAKE_FIND_FRAMEWORK=NEVER -DCMAKE_FIND_APPBUNDLE=NEVER -DCMAKE_FIND_USE_CMAKE_SYSTEM_PATH=FALSE -DCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH=FALSE -DMPI_CXX_COMPILER=/opt/homebrew/bin/mpicxx -DMPI_C_COMPILER=/opt/homebrew/bin/mpicc -DCMAKE_CXX_COMPILER=/opt/homebrew/bin/g++-11 -DCMAKE_C_COMPILER=/opt/homebrew/bin/gcc-11
The most common solution is to just set CMAKE_PREFIX_PATH to /opt/homebrew. CMake will then look preferentially in /opt/homebrew for everything. Since you're on Apple, you might need to set CMAKE_FIND_FRAMEWORK and CMAKE_FIND_APPBUNDLE to LAST or NEVER, too.
You can skip the standard platform search paths by setting CMAKE_FIND_USE_CMAKE_SYSTEM_PATH to FALSE at the command line, in a preset, or in a toolchain file. You might also wish to disable looking at the PATH environment variable by setting CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH to FALSE.
Finally, if you're in a cross-compiling scenario or toolchain file, you can change the definition of the system directories by setting CMAKE_SYSROOT. Note that the sysroot will have to contain the language runtime libraries (e.g. glibc) and will be passed to the --sysroot flag (or equivalent). Just be aware of those effects, too.
All of this is documented here:
https://cmake.org/cmake/help/latest/command/find_package.html#search-procedure
https://cmake.org/cmake/help/latest/variable/CMAKE_FIND_FRAMEWORK.html#variable:CMAKE_FIND_FRAMEWORK
https://cmake.org/cmake/help/latest/variable/CMAKE_FIND_APPBUNDLE.html#variable:CMAKE_FIND_APPBUNDLE
The following homebrew.cmake toolchain file worked for me:
set(HOMEBREW_PREFIX "/usr/local"
CACHE PATH "Path to Homebrew installation")
set(CMAKE_C_COMPILER "${HOMEBREW_PREFIX}/bin/gcc-11")
set(CMAKE_CXX_COMPILER "${HOMEBREW_PREFIX}/bin/g++-11")
set(CMAKE_PREFIX_PATH
"${HOMEBREW_PREFIX}"
# These libraries are keg-only and not loaded into
# the root prefix by default (to avoid clashes).
"${HOMEBREW_PREFIX}/opt/lapack"
"${HOMEBREW_PREFIX}/opt/openblas"
"${HOMEBREW_PREFIX}/opt/gcc/lib/gcc/11"
)
list(TRANSFORM CMAKE_PREFIX_PATH APPEND "/include"
OUTPUT_VARIABLE CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES)
set(CMAKE_C_STANDARD_INCLUDE_DIRECTORIES "${CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES}")
set(CMAKE_FIND_FRAMEWORK NEVER)
set(CMAKE_FIND_APPBUNDLE NEVER)
set(CMAKE_FIND_USE_CMAKE_SYSTEM_PATH FALSE)
set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH FALSE)
I built with the following commands:
$ ls
tRecX homebrew.cmake
$ cmake -G Ninja -S tRecX -B tRecX-build \
-DCMAKE_TOOLCHAIN_FILE=$PWD/homebrew.cmake \
-DCBLAS=/usr/local/opt/openblas/lib/libblas.dylib \
-DCMAKE_EXE_LINKER_FLAGS="-Wl,-undefined,dynamic_lookup" \
-DCMAKE_SHARED_LINKER_FLAGS="-Wl,-undefined,dynamic_lookup" \
-DCMAKE_BUILD_TYPE=Parallel
[ ... output clipped ... ]
Boost found -- full functionality
Build "Parallel" with C++ flags -D_USE_BOOST_ -O3 -pthread -D_USE_FFTW_, return to default by -UCMAKE_BUILD_TYPE
Compiler: /usr/local/bin/g++-11, change by -DCMAKE_CXX_COMPILER=[path_to_complier]
-- Linking to libraries Boost::system;Boost::filesystem;/usr/local/lib/libfftw3.dylib;/usr/local/opt/gcc/lib/gcc/11/libgfortran.dylib;alglib;/usr/local/lib/libarpack.dylib;Boost::system;Boost::filesystem;/usr/local/opt/lapack/lib/liblapacke.dylib;/usr/local/opt/openblas/lib/libblas.dylib;/usr/local/opt/lapack/lib/liblapack.dylib;/usr/local/opt/lapack/lib/libblas.dylib;m
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/alexreinking/Development/tRecX-build
$ cmake --build tRecX-build
I had to set CBLAS manually because libblas.dylib provides the OpenBLAS CBLAS interface, but the build system specifically looks for a library named libcblas. There's no other option in this case.
The code and build have issues with its linking model and dependencies. I was able to paper over these by setting -Wl,-undefined,dynamic_lookup. However, note that this will just defer linker errors to runtime and might impose a large startup cost.
If you can make commits to the project, I would store these settings in a preset, maybe name it homebrew-parallel or something:
-DCMAKE_TOOLCHAIN_FILE=$PWD/homebrew.cmake \
-DCBLAS=/usr/local/opt/openblas/lib/libblas.dylib \
-DCMAKE_EXE_LINKER_FLAGS="-Wl,-undefined,dynamic_lookup" \
-DCMAKE_SHARED_LINKER_FLAGS="-Wl,-undefined,dynamic_lookup" \
-DCMAKE_BUILD_TYPE=Parallel
Then you could just run cmake --preset=homebrew-parallel

CMake with MinGW-w64 does not install built DLL, but it's being built fine

NB: The files referenced here are all given below the horizontal ruler a bit down.
This is the MWE derived from a project where I ran into this. CMake version used is 3.12.2 on Ubuntu 16.04 (16.04.6 to be precise).
The goal is to create a CMakeLists.txt which can be re-targeted to build a Windows DLL using the MinGW-w64 toolchain (apt-get install mingw-w64 on Ubuntu/Debian).
When using no explicit toolchain file (i.e. without -DCMAKE_TOOLCHAIN_FILE=...), all works as expected and the lib${PRJNAME}.so gets installed as desired. However, once I use the toolchain file given below, I only get the resulting import lib ${PRJNAME}Lib.dll.a but not the corresponding .dll file installed.
If I invoke the Bash script as follows:
./build.sh 2>&1 |grep '^-- Install'
the output is:
-- Install configuration: ""
-- Installing: /home/user/cmake-test/build-native/install-target/lib/libtest.so
-- Install configuration: ""
-- Installing: /home/user/cmake-test/build-windows/install-target/lib/test.dll.a
As you can see the native build installs the actual shared library, but the one targeting Windows only installs the import lib, not the DLL. What I'd expect to see is something like this:
-- Install configuration: ""
-- Installing: /home/user/cmake-test/build-native/install-target/lib/libtest.so
-- Install configuration: ""
-- Installing: /home/user/cmake-test/build-windows/install-target/lib/test.dll
-- Installing: /home/user/cmake-test/build-windows/install-target/lib/test.dll.a
What is it I am doing wrong here? It would seem that the install() function is invoked properly:
install(
TARGETS ${PRJNAME}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT library
)
Clearly ARCHIVE DESTINATION takes effect as that's where the import lib ends up. But why is the built .dll completely ignored here?
Side-note: I am aware of GNUInstallDirs, but that fell totally apart once I started cross-compiling for Windows. So I am setting the desired paths "manually" before invoking install().
build.sh (should be executable)
The script will first wipe the folders build-native and build-windows, if present, and then create those again. Then it will invoke cmake from these folders respectively, targeting using the system (native) toolchain and the MinGW-w64 toolchain respectively. Last but not least it will invoke the installation from these folders respectively.
So if you place this into an empty folder along with the other files this should not meddle with your data elsewhere in any way.
#/usr/bin/env bash
for i in native windows; do
D=build-$i
test -d $D && rm -rf $D
mkdir $D
[[ "$i" == "windows" ]] && TCFILE=mingw64-64bit.cmake
( set -x; cd $D && cmake .. -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=. ${TCFILE+-DCMAKE_TOOLCHAIN_FILE=$TCFILE} -DCMAKE_VERBOSE_MAKEFILE=ON )
( set -x; cd $D && cmake --build . --target install )
done
test.cpp
#ifdef _WIN32
# if defined(test_EXPORTS)
# define TEST_API __declspec(dllexport)
# else
# define TEST_API __declspec(dllimport)
# endif
#else
# define TEST_API
#endif
TEST_API void SomeFunction()
{
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.12)
set(PRJNAME test)
set(TARGET_DIR "${CMAKE_CURRENT_BINARY_DIR}/install-target")
project(${PRJNAME})
add_library(${PRJNAME} SHARED test.cpp)
if(CMAKE_SYSTEM_NAME MATCHES "Windows")
set(DLL_PREFIX)
set(DLL_POSTFIX Lib)
else()
set(DLL_PREFIX lib)
set(DLL_POSTFIX)
endif()
set_target_properties(
${PRJNAME}
PROPERTIES
PREFIX "${DLL_PREFIX}"
IMPORT_PREFIX "${DLL_PREFIX}"
DEBUG_POSTFIX "${DLL_POSTFIX}"
RELEASE_POSTFIX "${DLL_POSTFIX}"
CXX_STANDARD 11
CXX_EXTENSIONS OFF
CXX_STANDARD_REQUIRED ON
POSITION_INDEPENDENT_CODE 1
)
set(CMAKE_INSTALL_PREFIX ${TARGET_DIR})
set(CMAKE_INSTALL_LIBDIR lib)
set(CMAKE_INSTALL_INCLUDEDIR include)
install(
TARGETS ${PRJNAME}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT library
)
mingw64-64bit.cmake
set(CMAKE_SYSTEM_NAME Windows)
set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc-posix)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++-posix)
set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
install(
TARGETS ${PRJNAME}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT library
)
According to the install command documentation the DLL file is considered a runtime object. I tested the example on Ubuntu 14.04.

correctly set the location of imported cmake targets for an installed package

I would like to be able to import targets from an installed library but
when using:
install(TARGETS
foobar
EXPORT foobarLibTargets
LIBRARY DESTINATION lib)
cmake generates a foobarLibTargets.cmake containing an absolute path:
set_target_properties(foobar PROPERTIES
IMPORTED_LOCATION_NOCONFIG "/where/I/happened/to/build/libfoobar.so"
IMPORTED_SONAME_NOCONFIG "libfoobar.so"
)
Such that a build using the imported target from the installation will fail as the path does not exist.
Q How can I get it to use the correct relative location instead?
This would be equivalent to:
set_target_properties(foobar PROPERTIES
IMPORTED_LOCATION_NOCONFIG "#PACKAGE_LIBRARY_INSTALL_DIR#/libfoobar.so")
If I look at another project which does something similar but works it has:
set_target_properties(foobar PROPERTIES
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libfoobar.so"
IMPORTED_SONAME_RELEASE "libfoobar.so"
)
Here are some example files that reproduce the issue:
CMakeLists.txt:
cmake_minimum_required(VERSION 3.7)
project(FOOBAR VERSION 1.2.3)
set(VERSION 1.2.3)
set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib:$ORIGIN/")
set(CMAKE_INSTALL_PREFIX "/opt/foobar" CACHE PATH "Install path prefix" FORCE)
add_library(foobar SHARED
foobar.cpp
)
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 0)
set(CPACK_PACKAGE_NAME "foobar")
set(CPACK_PACKAGE_VERSION ${VERSION})
set(CPACK_PACKAGING_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX})
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
include(CPack)
# Indicate the content of the distribution pakcages
install(FILES
${CMAKE_SOURCE_DIR}/foobar.h
DESTINATION include
)
install(TARGETS
foobar
EXPORT foobarLibTargets
LIBRARY DESTINATION lib)
include(CMakePackageConfigHelpers)
set(ConfigFileInstallDir lib/cmake/foobar)
set(INCLUDE_INSTALL_DIR include)
set(LIBRARY_INSTALL_DIR lib)
message(STATUS "CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}")
configure_package_config_file(foobarConfig.cmake.in
"${CMAKE_BINARY_DIR}/foobarConfig.cmake"
INSTALL_DESTINATION "${ConfigFileInstallDir}"
PATH_VARS INCLUDE_INSTALL_DIR LIBRARY_INSTALL_DIR)
write_basic_package_version_file(
"${CMAKE_BINARY_DIR}/foobarConfigVersion.cmake"
VERSION "${VERSION}"
COMPATIBILITY ExactVersion)
export(EXPORT foobarLibTargets
FILE "${CMAKE_CURRENT_BINARY_DIR}/foobarLibTargets.cmake")
install(EXPORT foobarLibTargets
FILE foobarTargets.cmake
DESTINATION lib/cmake)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/foobarConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/foobarConfigVersion.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/foobarLibTargets.cmake"
DESTINATION "${ConfigFileInstallDir}")
foobarConfig.cmake.in:
set(FOOBAR_VERSION #VERSION#)
#PACKAGE_INIT#
set_and_check(FOOBAR_INCLUDE_DIR "#PACKAGE_INCLUDE_INSTALL_DIR#")
set_and_check(FOOBAR_LIBRARY "#PACKAGE_LIBRARY_INSTALL_DIR#/libfoobar.so")
set_and_check(FOOBAR_LIBRARY_DIR "#PACKAGE_LIBRARY_INSTALL_DIR#")
include("${CMAKE_CURRENT_LIST_DIR}/foobarLibTargets.cmake")
# workaround - correct absolute path in the above
# this shouldn't be necessary (hence this question)
#set_target_properties(foobar PROPERTIES
# IMPORTED_LOCATION_NOCONFIG "#PACKAGE_LIBRARY_INSTALL_DIR#/libfoobar.so"
#)
foobar.h:
void hello();
foobar.cpp:
#include <iostream>
void hello() {
std::cerr << "hello world\n";
}
useFoo.cmake (a CMakeLists.txt for an example project using the installed library):
cmake_minimum_required(VERSION 3.7)
project(useFoo VERSION 1.2.3)
set(VERSION 1.2.3)
find_package(foobar)
file(GENERATE OUTPUT foobar-gen CONTENT "<TARGET_FILE:foobar>=$<TARGET_FILE:foobar>\n")
message(STATUS "FOOBAR_LIBRARY_DIR=${FOOBAR_LIBRARY_DIR}")
message(STATUS "FOOBAR_INCLUDE_DIR=${FOOBAR_INCLUDE_DIR}")
build.sh (build and use the installation package):
#!/bin/sh
rm -rf target
mkdir target
cd target
cmake .. &&
make &&
cpack -G TGZ
if [ $? -ne 0 ]; then
echo "doh!"
exit 1
fi
cd ..
rm -rf install
mkdir install
cd install
tar -xvzf ../target/foobar-1.2.3.tar.gz
cp ../useFoo.cmake CMakeLists.txt
export CMAKE_PREFIX_PATH=`pwd`/opt/foobar/lib/cmake:`pwd`/opt/foobar/lib/cmake/foobar
cmake .
if [ $? -ne 0 ]; then
echo "doh!"
exit 1
fi
cat foobar-gen
The output of cat foobar-gen is:
<TARGET_FILE:foobar>=/where/I/happened/to/build/libfoobar.so
I would like it to be:
<TARGET_FILE:foobar>=/where/I/actually/installed/libfoobar.so
Which it becomes if I uncomment the workaround.
Is there a way which avoids the workaround?
The related question - Strange issue with variables in a config-file cmake package - has similar code which both reproduces this issue and adds another one on top.
The main issue is that the two files foobarLibTargets.cmake and foobarTargets.cmake were both installed and the wrong one was picked up.
You will find below an improved project along with remarks to better organize the build system.
ChangeLog summarizing edits
2019-05-25
Create GitHub project to streamline reuse and adaptation. See https://github.com/jcfr/stackoverflow-56135785-answer
Rename project and source directory from foobar to FooBarLib, update Suggestions section accordingly
Improve build.sh
Updated suggestions (CPACK_PACKAGING_INSTALL_PREFIX should be absolute)
RPM:
Add support for building RPM package using make package
Update build.sh to display content of RPM package
Remarks
Two config files should be generated:
one for the build tree: this allow user of your project to directly build against your project and import targets
one for the install tree (which also end up being packaged)
Do not force the value of CMAKE_INSTALL_PREFIX
CPACK_PACKAGING_INSTALL_PREFIX should NOT be set to an absolute directory
For sake of consistency, use foobarTargets instead of foobarLibTargets
<projecname_uc> placeholder used below correspond to the name of the project upper-cased (ABC instead of abc)
To allow configuring your project when vendorized along other one, prefer variable with <projecname_uc>_. This means <projecname_uc>_INSTALL_LIBRARY_DIR is better than LIBRARY_INSTALL_DIR.
To allow user of the project to configure *_INSTALL_DIR variables, wrap them around if(DEFINED ...)
Consistently use variables (e.g LIBRARY_INSTALL_DIR should always be used instead of lib)
Prefer naming variable <projecname_uc>_INSTALL_*_DIR instead of <projecname_uc>_*_INSTALL_DIR, it make it easier to know the purpose of the variable when reading the code.
Since version is already associated with the project, there is no need to set VERSION variable. Instead, you can use PROJECT_VERSION or FOOBAR_VERSION
If starting a new project, prefer the most recent CMake version. CMake 3.13 instead of CMake 3.7
Introduced variable <projecname_uc>_INSTALL_CONFIG_DIR
<project_name>Targets.cmake should not be installed using install(FILES ...), it is already associated with an install rule
conditionally set CMAKE_INSTALL_RPATH, it is valid only on Linux
<project_name>Config.cmake.in:
there is no need to set FOOBAR_LIBRARY, this information is already associated with the exported foobar target
FOOBAR_LIBRARY_DIR is also not needed, this information is already associated with the exported foobar target
instead of setting FOOBAR_INCLUDE_DIR, the command target_include_directories should be used
remove setting of FOOBAR_VERSION, the generate version file already takes care of setting the version.
always specify ARCHIVE, LIBRARY and RUNTIME when declaring install rules for target. It avoid issue when switching library type. One less thing to think about.
always specify component with your install rule. It allows user of your project to selectively install part of it only development component or only runtime one, ...
initializing CMAKE_BUILD_TYPE is also important, it ensures the generated Targets file are associated with a configuration (instead of having the suffix -noconfig.cmake)
Suggested changes
Generally speaking, I recommend to have a source tree, a build tree and install tree. The files posted below assumed the following layout:
./build.sh
./FooBarLib/FooBarLibConfig.cmake.in
./FooBarLib/CMakeLists.txt
./FooBarLib/foobar.cpp
./FooBarLib/foobar.h
./FooBarLib-build
./FooBarLib-install
./useFoo/CMakeLists.txt
./useFoo-build
build.sh
#!/bin/bash
set -xeu
set -o pipefail
script_dir=$(cd $(dirname $0) || exit 1; pwd)
project_name=FooBarLib
archive_name=${project_name}
# cleanup ${project_name}-build
cd $script_dir
rm -rf ${project_name}-build
mkdir ${project_name}-build
cd ${project_name}-build
# configure, build and package ${project_name}
cmake ../${project_name}
make
make package # equivalent to running "cpack -G TGZ" and "cmake -G RPM"
# extract ${project_name} archive
cd $script_dir
rm -rf ${project_name}-install
mkdir ${project_name}-install
cd ${project_name}-install
tar -xvzf ../${project_name}-build/${archive_name}-1.2.3.tar.gz
# cleanup useFoo-build
cd $script_dir
rm -rf useFoo-build
mkdir useFoo-build
cd useFoo-build
cpack_install_prefix=/opt
# configure useFoo
cmake -D${project_name}_DIR=$script_dir/${project_name}-install${cpack_install_prefix}/lib/cmake/${project_name}/ ../useFoo
cat foobar-gen
# display content of RPM. If command "rpmbuild" is available, RPM package is expected.
if command -v rpmbuild &> /dev/null; then
rpm -qlp $script_dir/${project_name}-build/${archive_name}-1.2.3.rpm
fi
FooBarLib/CMakeLists.txt
cmake_minimum_required(VERSION 3.13)
project(FooBarLib VERSION 1.2.3)
if(UNIX AND NOT APPLE)
set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib:$ORIGIN/")
endif()
#------------------------------------------------------------------------------
# Set a default build type if none was specified
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to 'Release' as none was specified.")
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build." FORCE)
mark_as_advanced(CMAKE_BUILD_TYPE)
# Set the possible values of build type for cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()
#------------------------------------------------------------------------------
# This variable controls the prefix used to generate the following files:
# <export_config_name>ConfigVersion.cmake
# <export_config_name>Config.cmake
# <export_config_name>Targets.cmake
# and it also used to initialize FOOBARLIB_INSTALL_CONFIG_DIR value.
set(export_config_name ${PROJECT_NAME})
#------------------------------------------------------------------------------
if(NOT DEFINED FOOBARLIB_INSTALL_INCLUDE_DIR)
set(FOOBARLIB_INSTALL_INCLUDE_DIR include)
endif()
if(NOT DEFINED FOOBARLIB_INSTALL_BIN_DIR)
set(FOOBARLIB_INSTALL_BIN_DIR bin)
endif()
if(NOT DEFINED FOOBARLIB_INSTALL_LIBRARY_DIR)
set(FOOBARLIB_INSTALL_LIBRARY_DIR lib)
endif()
if(NOT DEFINED FOOBARLIB_INSTALL_CONFIG_DIR)
set(FOOBARLIB_INSTALL_CONFIG_DIR ${FOOBARLIB_INSTALL_LIBRARY_DIR}/cmake/${export_config_name})
endif()
#------------------------------------------------------------------------------
set(headers
foobar.h
)
# Install rule for headers
install(
FILES ${headers}
DESTINATION ${FOOBARLIB_INSTALL_INCLUDE_DIR}
COMPONENT Development
)
#------------------------------------------------------------------------------
add_library(foobar SHARED
foobar.cpp
)
target_include_directories(foobar
PUBLIC
$<BUILD_INTERFACE:${FooBarLib_SOURCE_DIR}>
$<INSTALL_INTERFACE:${FOOBARLIB_INSTALL_INCLUDE_DIR}>
)
install(
TARGETS foobar
EXPORT ${export_config_name}Targets
ARCHIVE DESTINATION ${FOOBARLIB_INSTALL_LIBRARY_DIR} COMPONENT Development
LIBRARY DESTINATION ${FOOBARLIB_INSTALL_LIBRARY_DIR} COMPONENT RuntimeLibraries
RUNTIME DESTINATION ${FOOBARLIB_INSTALL_BIN_DIR} COMPONENT RuntimeLibraries
)
#------------------------------------------------------------------------------
# Configure <export_config_name>ConfigVersion.cmake common to build and install tree
include(CMakePackageConfigHelpers)
set(config_version_file ${PROJECT_BINARY_DIR}/${export_config_name}ConfigVersion.cmake)
write_basic_package_version_file(
${config_version_file}
VERSION "${FooBarLib_VERSION}"
COMPATIBILITY ExactVersion
)
#------------------------------------------------------------------------------
# Export '<export_config_name>Targets.cmake' for a build tree
export(
EXPORT ${PROJECT_NAME}Targets
FILE "${CMAKE_CURRENT_BINARY_DIR}/${export_config_name}Targets.cmake"
)
# Configure '<export_config_name>Config.cmake' for a build tree
set(build_config ${CMAKE_BINARY_DIR}/${export_config_name}Config.cmake)
configure_package_config_file(
${export_config_name}Config.cmake.in
${build_config}
INSTALL_DESTINATION "${PROJECT_BINARY_DIR}"
)
#------------------------------------------------------------------------------
# Export '<export_config_name>Targets.cmake' for an install tree
install(
EXPORT ${export_config_name}Targets
FILE ${export_config_name}Targets.cmake
DESTINATION ${FOOBARLIB_INSTALL_CONFIG_DIR}
)
set(install_config ${PROJECT_BINARY_DIR}/CMakeFiles/${export_config_name}Config.cmake)
configure_package_config_file(
${export_config_name}Config.cmake.in
${install_config}
INSTALL_DESTINATION ${FOOBARLIB_INSTALL_CONFIG_DIR}
)
# Install config files
install(
FILES ${config_version_file} ${install_config}
DESTINATION "${FOOBARLIB_INSTALL_CONFIG_DIR}"
)
#------------------------------------------------------------------------------
# Generate package
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 0)
set(CPACK_PACKAGE_NAME "${PROJECT_NAME}")
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
# Setting this variable also impacts the layout of TGZ.
set(CPACK_PACKAGING_INSTALL_PREFIX "/opt")
# Setting CPACK_SOURCE_* and CPACK_GENERATOR allow to have "make package" generates
# the expected archive.
# Disable source generator enabled by default
set(CPACK_SOURCE_TBZ2 OFF CACHE BOOL "Enable to build TBZ2 source packages" FORCE)
set(CPACK_SOURCE_TGZ OFF CACHE BOOL "Enable to build TGZ source packages" FORCE)
set(CPACK_SOURCE_TZ OFF CACHE BOOL "Enable to build TZ source packages" FORCE)
# Select generators
if(UNIX AND NOT APPLE)
set(CPACK_GENERATOR "TGZ")
find_program(RPMBUILD_PATH rpmbuild)
if(RPMBUILD_PATH)
list(APPEND CPACK_GENERATOR "RPM")
endif()
elseif(APPLE)
# ...
endif()
include(CPack)
FooBarLib/FooBarLibConfig.cmake.in
#PACKAGE_INIT#
set(export_config_name "#export_config_name#")
set_and_check(${export_config_name}_TARGETS "${CMAKE_CURRENT_LIST_DIR}/${export_config_name}Targets.cmake")
include(${${export_config_name}_TARGETS})
useFoo/CMakeLists.txt
cmake_minimum_required(VERSION 3.13)
project(useFoo VERSION 1.2.3)
find_package(FooBarLib REQUIRED)
file(GENERATE OUTPUT foobar-gen CONTENT "<TARGET_FILE:foobar>=$<TARGET_FILE:foobar>\n")
get_target_property(foobar_INCLUDE_DIR foobar INTERFACE_INCLUDE_DIRECTORIES)
message(STATUS "foobar_INCLUDE_DIR=${foobar_INCLUDE_DIR}")
get_target_property(imported_location foobar IMPORTED_LOCATION_RELEASE)
get_filename_component(foobar_LIBRARY_DIR ${imported_location} DIRECTORY)
message(STATUS "foobar_LIBRARY_DIR=${foobar_LIBRARY_DIR}")
Output of build.sh
./build.sh
+ set -o pipefail
+++ dirname ./build.sh
++ cd .
++ pwd
+ script_dir=/tmp/stackoverflow-56135785-answer
+ project_name=FooBarLib
+ archive_name=FooBarLib
+ cd /tmp/stackoverflow-56135785-answer
+ rm -rf FooBarLib-build
+ mkdir FooBarLib-build
+ cd FooBarLib-build
+ cmake ../FooBarLib
-- The C compiler identification is GNU 4.8.5
-- The CXX compiler identification is GNU 4.8.5
-- 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
-- Setting build type to 'Release' as none was specified.
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/stackoverflow-56135785-answer/FooBarLib-build
+ make
Scanning dependencies of target foobar
[ 50%] Building CXX object CMakeFiles/foobar.dir/foobar.cpp.o
[100%] Linking CXX shared library libfoobar.so
[100%] Built target foobar
+ make package
[100%] Built target foobar
Run CPack packaging tool...
CPack: Create package using TGZ
CPack: Install projects
CPack: - Run preinstall target for: FooBarLib
CPack: - Install project: FooBarLib
CPack: Create package
CPack: - package: /tmp/stackoverflow-56135785-answer/FooBarLib-build/FooBarLib-1.2.3.tar.gz generated.
CPack: Create package using RPM
CPack: Install projects
CPack: - Run preinstall target for: FooBarLib
CPack: - Install project: FooBarLib
CPack: Create package
-- CPackRPM:Debug: Using CPACK_RPM_ROOTDIR=/tmp/stackoverflow-56135785-answer/FooBarLib-build/_CPack_Packages/Linux/RPM
CPackRPM: Will use GENERATED spec file: /tmp/stackoverflow-56135785-answer/FooBarLib-build/_CPack_Packages/Linux/RPM/SPECS/foobarlib.spec
CPack: - package: /tmp/stackoverflow-56135785-answer/FooBarLib-build/FooBarLib-1.2.3.rpm generated.
+ cd /tmp/stackoverflow-56135785-answer
+ rm -rf FooBarLib-install
+ mkdir FooBarLib-install
+ cd FooBarLib-install
+ tar -xvzf ../FooBarLib-build/FooBarLib-1.2.3.tar.gz
opt/
opt/include/
opt/include/foobar.h
opt/lib/
opt/lib/libfoobar.so
opt/lib/cmake/
opt/lib/cmake/FooBarLib/
opt/lib/cmake/FooBarLib/FooBarLibTargets.cmake
opt/lib/cmake/FooBarLib/FooBarLibTargets-release.cmake
opt/lib/cmake/FooBarLib/FooBarLibConfigVersion.cmake
opt/lib/cmake/FooBarLib/FooBarLibConfig.cmake
+ cd /tmp/stackoverflow-56135785-answer
+ rm -rf useFoo-build
+ mkdir useFoo-build
+ cd useFoo-build
+ cpack_install_prefix=/opt
+ cmake -DFooBarLib_DIR=/tmp/stackoverflow-56135785-answer/FooBarLib-install/opt/lib/cmake/FooBarLib/ ../useFoo
-- The C compiler identification is GNU 4.8.5
-- The CXX compiler identification is GNU 4.8.5
-- 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
-- foobar_INCLUDE_DIR=/tmp/stackoverflow-56135785-answer/FooBarLib-install/opt/include
-- foobar_LIBRARY_DIR=/tmp/stackoverflow-56135785-answer/FooBarLib-install/opt/lib
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/stackoverflow-56135785-answer/useFoo-build
+ cat foobar-gen
<TARGET_FILE:foobar>=/tmp/stackoverflow-56135785-answer/FooBarLib-install/opt/lib/libfoobar.so
+ command -v rpmbuild
+ rpm -qlp /tmp/stackoverflow-56135785-answer/FooBarLib-build/FooBarLib-1.2.3.rpm
/opt
/opt/include
/opt/include/foobar.h
/opt/lib
/opt/lib/cmake
/opt/lib/cmake/FooBarLib
/opt/lib/cmake/FooBarLib/FooBarLibConfig.cmake
/opt/lib/cmake/FooBarLib/FooBarLibConfigVersion.cmake
/opt/lib/cmake/FooBarLib/FooBarLibTargets-release.cmake
/opt/lib/cmake/FooBarLib/FooBarLibTargets.cmake
/opt/lib/libfoobar.so
Only after instrumenting the source of cmake itself was I finally able to track this down.
The export and install commands are both capable of generating cmake files for targets.
The export command e.g.:
export(EXPORT foobarLibTargets
FILE "${CMAKE_CURRENT_BINARY_DIR}/foobarLibTargets.cmake")
creates a Targets.cmake referencing the build tree.
The install command e.g.:
install(EXPORT foobarLibTargets
FILE foobarTargets.cmake
DESTINATION lib/cmake)
creates a Targets.cmake referencing the relocatable install location.
This is essentially what #J-Christophe meant by saying that two files were installed and the wrong one was picked up.
I had wrongly assumed that the install command was only responsible for installing files and the export command was only responsible for generating them.
The documentation makes sense now
export(EXPORT [NAMESPACE ] [FILE ])
The file created by this command is specific to the build tree and
should never be installed. See the install(EXPORT) command to export
targets from an installation tree.
The workaround I had previously is no longer necesary.
For reference this was to explicitly set the correct location in the package's Config.cmake as in:
set(FOOBAR_VERSION #VERSION#)
#PACKAGE_INIT#
set_and_check(FOOBAR_INCLUDE_DIR "#PACKAGE_INCLUDE_INSTALL_DIR#")
set_and_check(FOOBAR_LIBRARY "#PACKAGE_LIBRARY_INSTALL_DIR#/libfoobar.so")
set_and_check(FOOBAR_LIBRARY_DIR "#PACKAGE_LIBRARY_INSTALL_DIR#")
include("${CMAKE_CURRENT_LIST_DIR}/foobarLibTargets.cmake")
# workaround - correct absolute path in the above
# this shouldn't be necessary!
set_target_properties(foobar PROPERTIES
IMPORTED_LOCATION_NOCONFIG "#PACKAGE_LIBRARY_INSTALL_DIR#/libfoobar.so"
)
Most of the solutions here are misleading. It's by design working that way: https://github.com/Kitware/CMake/blob/f46c67de0e16293a40bbbade18aa7cee9edb02b0/Source/cmExportInstallFileGenerator.cxx#L184-L192
So if the DESTINATION in the install(EXPORT ...) statement is an absolute path, then hardcode it as absolute path in the exported package config files. Otherwise, generate the path dynamically using _IMPORT_PREFIX.

STM32 Project with CMake

I am trying to create and compile an ARM-based STM32 project using CMake.
CMakeLsts.txt is the following:
cmake_minimum_required(VERSION 3.7)
SET(CMAKE_SYSTEM_NAME Generic)
SET(CMAKE_SYSTEM_VERSION 1)
# Enable logging messages
#set(CMAKE_VERBOSE_MAKEFILE ON)
# Project name
set(PROJECT_NAME FixtureTACO)
PROJECT(${PROJECT_NAME} C CXX ASM)
SET(CMAKE_CXX_STANDARD 11)
###################### CHIP CONFIGURATION ##########################
SET(ROOT_PROJ ${CMAKE_CURRENT_SOURCE_DIR})
SET(CPU "cortex-m4")
SET(ARCH_NAME "arm")
SET(ARCH_VER "v7e-m")
SET(FAMILY "stm32f3")
SET(CHIP "STM32F303xC")
SET(ARCH "${ARCH_NAME}${ARCH_VER}")
####################################################################
# MCU Config
set(FPU "-mfpu=fpv4-sp-d16")
set(FLOAT_ABI "-mfloat-abi=hard")
# Toolchain path
set(TOOLCHAIN_PATH "")
set(ARM_LIB "/usr/lib/arm-none-eabi/lib/${ARCH}")
# Specify C, C++ and ASM compilers
SET(CMAKE_C_COMPILER ${TOOLCHAIN_PATH}arm-none-eabi-gcc)
SET(CMAKE_CXX_COMPILER ${TOOLCHAIN_PATH}arm-none-eabi-g++)
set(AS ${TOOLCHAIN_PATH}arm-none-eabi-as)
set(AR ${TOOLCHAIN_PATH}arm-none-eabi-ar)
set(OBJCOPY ${TOOLCHAIN_PATH}arm-none-eabi-objcopy)
set(OBJDUMP ${TOOLCHAIN_PATH}arm-none-eabi-objdump)
set(SIZE ${TOOLCHAIN_PATH}arm-none-eabi-size)
set(GDB ${TOOLCHAIN_PATH}arm-none-eabi-gdb)
set(SIZE ${TOOLCHAIN_PATH}arm-none-eabi-size)
# Definitions passed at compile time (#defines)
add_definitions(-DFAMILY=${FAMILY})
add_definitions(-DCHIP=${CHIP})
add_definitions(-D${CHIP})
add_definitions(-DUSE_FULL_LL_DRIVER)
add_definitions(-USE_HAL_DRIVER)
add_definitions(-DHSE_VALUE=8000000)
add_definitions(-DHSE_STARTUP_TIMEOUT=100)
add_definitions(-DLSE_STARTUP_TIMEOUT=5000)
add_definitions(-DLSE_VALUE=32768)
add_definitions(-DHSI_VALUE=8000000)
add_definitions(-DLSI_VALUE=40000)
add_definitions(-DDD_VALUE=3300)
add_definitions(-DPREFETCH_ENABLE=1)
# Compilation flags
add_compile_options(-mcpu=${CPU})
add_compile_options(-march=${ARCH})
add_compile_options(-mthumb)
add_compile_options(${FPU})
add_compile_options(${FLOAT_ABI})
add_compile_options(-Og)
add_compile_options(-Wall)
add_compile_options(-fdata-sections)
add_compile_options(-ffunction-sections)
# Only for debugging
add_compile_options(-g -gdwarf-2)
# Linker script path
file(GLOB_RECURSE LINKER_SCRIPT ${ROOT_PROJ}/platforms/${FAMILY}/Linker/*.ld)
# Variables initialized first time
SET(CMAKE_CXX_FLAGS_INIT "-std=c++11")
SET(CMAKE_C_FLAGS_INIT "-std=gnu99")
################################## Source code ###############################################################
# Retrieve all sources # "platforms/${FAMILY}/Startup/*.s"
file(GLOB SOURCES "platforms/${FAMILY}/Startup/*.s" "src/*.cpp" "src/*.c" "platforms/${FAMILY}/Hal/src/*.c" "platforms/${FAMILY}/Device/*.c")
#Retrieve all locations of headers
file(GLOB_RECURSE HEADERS "includes/*.h" "src/*.h" "platforms/${FAMILY}*.h")
set (INCLUDE_DIRS "")
foreach (_headerFile ${HEADERS})
get_filename_component(_dir ${_headerFile} PATH)
list (APPEND INCLUDE_DIRS ${_dir})
endforeach()
list(REMOVE_DUPLICATES INCLUDE_DIRS)
include_directories(${INCLUDE_DIRS})
link_directories(${ARM_LIB})
################################## Source code END ###########################################################
set(EXE_NAME "${PROJECT_NAME}_${CHIP}")
add_executable(${EXE_NAME}.elf ${SOURCES} ${LINKER_SCRIPT})
set(CMAKE_EXE_LINKER_FLAGS "-mcpu=${CPU} -mthumb ${FPU} ${FLOAT_ABI} --specs=nano.specs -T${LINKER_SCRIPT} -Wl,-Map=${PROJECT_BINARY_DIR}/${PROJECT_NAME}.map,--cref -Wl,--gc-sections")
# Libs and external dependencies
target_link_libraries(${EXE_NAME}.elf -lc -lm -lnosys)
# Outputs
set(ELF_FILE ${PROJECT_BINARY_DIR}/${EXE_NAME}.elf)
set(HEX_FILE ${PROJECT_BINARY_DIR}/${EXE_NAME}.hex)
set(BIN_FILE ${PROJECT_BINARY_DIR}/${EXE_NAME}.bin)
add_custom_command(TARGET "${EXE_NAME}.elf" POST_BUILD
# Build .hex and .bin files
COMMAND ${OBJCOPY} -Obinary ${ELF_FILE} ${BIN_FILE}
COMMAND ${OBJCOPY} -Oihex ${ELF_FILE} ${HEX_FILE}
COMMENT "Building ${PROJECT_NAME}.bin and ${PROJECT_NAME}.hex"
# Copy files to a custom build directory
COMMAND ${CMAKE_COMMAND} -E copy ${ELF_FILE} "${ROOT_PROJ}/builds/${CHIP}/${EXE_NAME}.elf"
COMMAND ${CMAKE_COMMAND} -E copy ${HEX_FILE} "${ROOT_PROJ}/builds/${CHIP}/${EXE_NAME}.hex"
COMMAND ${CMAKE_COMMAND} -E copy ${BIN_FILE} "${ROOT_PROJ}/builds/${CHIP}/${EXE_NAME}.bin"
# Display sizes
COMMAND ${SIZE} --format=berkeley ${EXE_NAME}.elf ${EXE_NAME}.hex
COMMENT "Invoking: Cross ARM GNU Print Size"
)
add_custom_target(UPLOAD
${GDB} -iex "target remote tcp:127.0.0.1:3333"
-iex "monitor program ${EXE_NAME}.elf"
-iex "monitor reset init"
-iex "disconnect" -iex "quit ")
When I try to compile I am getting the following errors:
[ 82%] Building C object CMakeFiles/FixtureTACO_STM32F303xC.elf.dir/platforms/stm32f3/Hal/src/stm32f3xx_ll_utils.c.obj
[ 86%] Building ASM object CMakeFiles/FixtureTACO_STM32F303xC.elf.dir/platforms/stm32f3/Startup/startup_stm32f303xc.s.obj
cc: warning: ‘-mcpu=’ is deprecated; use ‘-mtune=’ or ‘-march=’ instead
cc: error: unrecognized command line option ‘-mthumb’; did you mean ‘-mtbm’?
cc: error: unrecognized command line option ‘-mfpu=fpv4-sp-d16’
cc: error: unrecognized command line option ‘-mfloat-abi=hard’
The error occurs ONLY when an assembly file (startup.s in this case) is present in source files and when FPU and FLOAR_ABI flags are present. As you can see, error occurs when startup_stm32f303xc.s is compiled.
I suspect that I am adding those flags in the wrong place but I have no clue where to add them in order to get it works.
Later edit: I already have installed arm 7 compiler on my ubuntu system. I can use it without specifying any path as it is already present in environment variables. I can compile without problems ARM code (from Makefiles) for other targets on machine. My problem is with cmake.
In your line set(TOOLCHAIN_PATH "") you must add a path to compiler. First go to get your free GCC ARM ToolChain. Download for your OS. and then just copy to your favorite location. If you using Linux you can use my path configurations:
1.) Copy gcc arm compirel to /opt/ directory:
sudo tar xjfv ~/Downloads/gcc-arm-none-eabi-7-2018-q2-update-linux.tar.bz2 -C /opt/
For more "sexy" path you can do symbolic link:
sudo ln -s /opt/gcc-arm-none-eabi-7-2018-q2-update/ /opt/gcc-arm-none-eabi
After that go to your CMakeLists.txt and rewrite your set command to:
set(TOOLCHAIN_PATH "/opt/gcc-arm-none-eabi/bin")
But there is better solution to build your project for STM32, but with already done stm32-cmake template project, specifically made for STM32 family. It is mush easier done with something working. You will also need two prerequisites STM32CubeMX installed and again GCC ARM ToolChain. If you want to know how to use this template just DM me and I will you give a quick guidance.
OK, I finally managed to figure it out!
I had to replace
set(AS ${TOOLCHAIN_PATH}arm-none-eabi-as)
with
set(CMAKE_ASM_COMPILER ${TOOLCHAIN_PATH}arm-none-eabi-gcc)
It is not a mistake, it is gcc compiler. You can also append these flags: -x assembler-with-cpp.
CMake didn't know about my custom ASM compiler so it was using default system ASM compiler unless I force it by writing CMAKE_ASM_COMPILER. Now the project is being build and works fine on microcontroller.
The other answers were ok, but had half of the solution. Only ASM filese were compiled with wrong compiler.
I think you try to compile code for ARM using x86 compiler. It will not work. You need to download the ARM toolchain and use the correct compiler.
-mcpu is depreciated in the x86 branch, but is not in the ARM branch
another options just not exist in the x86 compiler.

Force CMake to use absolute include path

I have a project whose directory layout looks like:
- src/ #Contains main source code
- ext/ #Contains external libraries and headers from GitHub
- CMakeLists.txt
The problem is that no matter what I do, CMake always seems to pass ext/ to the compiler as a relative path, like this:
/usr/bin/c++ -I../ext mysrc.cpp
I've tried doing both:
include_directories("${PROJECT_SOURCE_DIR}/ext")
include_directories("/home/user/project/ext")
But it doesn't seem to matter. The directory is always passed to -I as ../ext.
Why does this matter? At the end of my build I invoke gcov -r <source file> which tells gcov to generate coverage reports from my source file and any relative paths found within. As a result, gcov is going into ext/ and generating reports for tons of stuff I don't care about and it's taking up a lot of time. If CMake would instead pass in -I/home/user/project/ext then gcov -r would ignore everything in ext/.
As far as I can tell from:
https://cmake.org/cmake/help/v3.13/command/include_directories.html ... this isn't possible, but maybe I'm just missing something?
Edit: This appears to be a problem with specifically the ninja generator. When using the Unix Makefiles generator, everything is passed via absolute paths.
https://gitlab.kitware.com/cmake/cmake/issues/18666
Edit2:
user#antimony:~/cmake_test$ ls
CMakeLists.txt ext src
user#antimony:~/cmake_test$ cat CMakeLists.txt
project(Hello)
add_subdirectory(src)
user#antimony:~/cmake_test$ cat src/CMakeLists.txt
include_directories(
.
${PROJECT_SOURCE_DIR}/ext
)
add_executable(hello_world hello.cpp)
user#antimony:~/cmake_test$ cat src/hello.cpp
#include <useless.h>
int main()
{
hello h;
return 0;
}
user#antimony:~/cmake_test$ cat ext/useless.h
struct hello {
int x;
};
user#antimony:~/cmake_test$ ~/Downloads/cmake-3.13.1-Linux-x86_64/bin/cmake --version
cmake version 3.13.1
CMake suite maintained and supported by Kitware (kitware.com/cmake).
user#antimony:~/cmake_test$ mkdir build && cd build
user#antimony:~/cmake_test/build$ ~/Downloads/cmake-3.13.1-Linux-x86_64/bin/cmake .. -G Ninja
-- The C compiler identification is GNU 7.3.0
-- The CXX compiler identification is GNU 7.3.0
...
-- Build files have been written to: /home/user/cmake_test/build
user#antimony:~/cmake_test/build$ ninja -v
[1/2] /usr/bin/c++ -I../src/. -I../ext -MD -MT src/CMakeFiles/hello_world.dir/hello.o -MF src/CMakeFiles/hello_world.dir/hello.o.d -o src/CMakeFiles/hello_world.dir/hello.o -c ../src/hello.cpp
[2/2] : && /usr/bin/c++ -rdynamic src/CMakeFiles/hello_world.dir/hello.o -o src/hello_world && :
user#antimony:~/cmake_test/build$ cat build.ninja
# CMAKE generated file: DO NOT EDIT!
# Generated by "Ninja" Generator, CMake Version 3.13
# This file contains all the build statements describing the
# compilation DAG.
...
#############################################
# Order-only phony target for hello_world
build cmake_object_order_depends_target_hello_world: phony || src/CMakeFiles/hello_world.dir
build src/CMakeFiles/hello_world.dir/hello.o: CXX_COMPILER__hello_world ../src/hello.cpp || cmake_object_order_depends_target_hello_world
DEP_FILE = src/CMakeFiles/hello_world.dir/hello.o.d
INCLUDES = -I../src/. -I../ext
OBJECT_DIR = src/CMakeFiles/hello_world.dir
OBJECT_FILE_DIR = src/CMakeFiles/hello_world.dir
TARGET_COMPILE_PDB = src/CMakeFiles/hello_world.dir/
TARGET_PDB = src/hello_world.pdb
# =============================================================================
# Link build statements for EXECUTABLE target hello_world
The example shows what may be considered an in-source build. That is when the build directory is the same or a sub-directory of the src folder (not that there is a hard definition or anything, but this does trigger the ninja issue of using relative paths on the command line). Try mkdir ~/cmake_build && cd ~/cmake_build && cmake ~/cmake_test then it should use absolute paths for everything.
Either way there really isn't a specific way to force one or the other. In general cmake generators will use absolute paths for everything that ends up used on the command line. There seems to be issues with Ninja that prevent the generator from using absolute paths for in-source builds (https://github.com/ninja-build/ninja/issues/1251).