Set multiple paths to CMAKE_Fortran_MODULE_DIRECTORY - cmake

So I am trying to include an installed Fortran library to a CMake project. I know the directory where the module (.mod) file is located, but my project can't seem to find it unless I set CMAKE_Fortran_MODULE_DIRECTORY.
SET(LIB_INCLUDE_DIR /usr/local/include)
SET(EX_FILES main.f90 file1.f90 file2.f90)
INCLUDE_DIRECTORIES(${LIB_INCLUDE_DIR})
ADD_EXECUTABLE(test ${EX_FILES})
TARGET_LINK_LIBRARIES(test lib1)
Where the error is
use lib1
1
Fatal Error: Can't open module file 'lib1.mod' for reading at (1): No such file or directory
unless I include the line
SET(CMAKE_Fortran_MODULE_DIRECTORY ${LIB_INCLUDE_DIR})
And then it can find the file just fine. But I'm running into a little problem. By setting CMAKE_Fortran_MODULE_DIRECTORY, CMake tries to write all generated modules to this directory rather than the CMAKE_BINARY_DIR (where I would like it).
From the documentation, I know that CMAKE_Fortan_MODULE_DIRECTORY is meant to be set to specify where to write generated module files, but some compilers look to that directory to find modules. Is there any way to set multiple directories so that if it can't find in/write to one directory, it searches the second? When I try to set CMAKE_Fortran_MODULE_DIRECTORY to be multiple directories, it only looks at the first directory.
If it helps I am on a Ubuntu 14.04 LTS system using gfortran 4.8.4
EDIT:
So by Alexander Vogt's suggestion I ran with VERBOSE=1 and got
cd /home/user/Repos/build/src && gfortran -I/home/user/Repos/build/src -isystem /usr/local/include -c /home/user/Repos/test_project/src/main.f90 -o CMakeFiles/test.dir/main.f90.o
when I did NOT set CMAKE_Fortran_MODULE_DIRECTORY and
cd /home/user/Repos/build/src && gfortran -J/usr/local/include -I/home/user/Repos/build/src -isystem /usr/local/include -c /home/user/Repos/test_project/src/main.f90 -o CMakeFiles/test.dir/main.f90.o
when I did.
It seems the only difference is the -J flag, which sets exactly what CMAKE_Fortran_MODULE_DIRECTORY sets. Is there some flag that sets just where to look for compiled modules, and not where to put them?

Related

How can I properly configure the g++ include path with mingw64?

I have installed msys2/mingw64 because I need the g++ compiler. Now, I want to compile some c++ oce which requires openblas. I have installed the package using pacman -S mingw-w64-x86_64-openblas. However, compiling the code fails with
fatal error: cblas.h: No such file or directory
Clearly, the include path does not contain the headers from openblas which are located at C:\msys64\mings64\include\openblas. This is easy to fix by passing -I<include path> as an additional argument to g++.
Now, I was wondering whether there is an automated way to include include files/headers of installed packages in the g++ include path. The same problem also holds for libraries.
For example, pacman might be able to atomatically append these paths onto some environment variable which g++ checks.
The standard way to get compilation and linking options for a library on MSYS2 and other Unix-like systems is to run this command:
pkg-config --cflags --libs openblas
If you're just compiling, use --cflags by itself.
If you're just linking, use --libs by itself.
Here's an example Bash command you could use to compile a single-file program:
g++ foo.cpp $(pkg-config --cflags --libs openblas) -o foo

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 : Selecting mpich over openmpi

I am using cmake 3.10.2. I have both openmpi and mpich installed. However I need to load only mpich. So I found from the documentation the following
MPI_EXECUTABLE_SUFFIX
A suffix which is appended to all names that are being looked for.
For instance you may set this to .mpich or .openmpi to prefer the one
or the other on Debian and its derivatives.
My CMake file goes like this
set(MPI_EXECUTABLE_SUFFIX ".mpich")
FIND_PACKAGE(MPI REQUIRED)
INCLUDE_DIRECTORIES(${MPI_INCLUDE_DIRS})
LINK_DIRECTORIES(${MPI_LIBRARY_DIRS})
message(${MPI_INCLUDE_PATH})
However this shows
/usr/lib/x86_64-linux-gnu/openmpi/include/openmpi/usr/lib/x86_64-linux-gnu/openmpi/include...
Where am I going wrong. Could you please help me with this
Also
mpicc -show
gcc -I/usr/lib/x86_64-linux-gnu/openmpi/include/openmpi -I/usr/lib/x86_64-linux-gnu/openmpi/include/openmpi/opal/mca/event/libevent2022/libevent -I/usr/lib/x86_64-linux-gnu/openmpi/include/openmpi/opal/mca/event/libevent2022/libevent/include -I/usr/lib/x86_64-linux-gnu/openmpi/include -pthread -L/usr//lib -L/usr/lib/x86_64-linux-gnu/openmpi/lib -lmpi
mpicc.mpich -show
gcc -Wl,-Bsymbolic-functions -Wl,-z,relro -I/usr/include/mpich -L/usr/lib/x86_64-linux-gnu -lmpich
the best is to use modules for switch between openmpi and mpich:
$ module load mpich
$ module unload mpich
$ module load openmpi
http://modules.sourceforge.net/
The default mpicc is not your choice. You can specify it manually in the cmake file, or update the $PATH variable with your mpicc included before the default one. Personally, I installed the mpich in the /usr/local/ directory.
Regards

cmake finds package, but does not add to include path

I am trying to compile (on FreeBSD, if that matters) a program that uses cmake. The CMakeLists.txt contains the lines
find_package(GLUT REQUIRED)
include_directories(${CMAKE_CURRENT_BINARY_DIR} ${OPENGL32_INCLUDE_DIRS} ${GLUT_INCLUDE_DIRS})
and cmake does not report any errors, but when I run make afterwards, I get
[…]
/usr/bin/c++ -fopenmp -I/path/build -o CMakeFiles/scriptbots.dir/GLView.cpp.o -c /path/GLView.cpp
[…]
In file included from /path/GLView.cpp:2:
/path/GLView.cpp:10:21: error: GL/glut.h: No such file or directory
[…]
GL/glut.h exists in /usr/local/include, which is not given as -I argument to /usr/bin/c++.
Compiling works when I explicitly add -I/usr/local/include to CMakeFiles/scriptbots.dir/flags.make. What do I need to change to make the project compile without manually changing the flags file?
As per its documentation, FindGLUT sets variable GLUT_INCLUDE_DIR, not GLUT_INCLUDE_DIRS. Change this in your CMakeList and it should work.

Linking libs with make/g++ under ubuntu

lets say my makefile looks like this:
CXX = g++
OGLLIBS = -lglut32 -lglu32 -lopengl32
projname : projname.o
${CXX} -o projname $< ${OGLLIBS}
Then in which directory does g++ look for the libraries? I was assuming . but if I put the libs there it still complains about not finding them (*.lib is the correct file or does unix use another ending?!)
Folders
unix uses the folders /lib (for system lib) and /usr/lib
your own libraries or newly installed should be in /usr/local/lib but you need to add "-I/usr/local/lib" as compiler flag.
file ending
is .so for shared libs basicly
looking for libs
your can tell your compiler to add other directories to look for libs by setting a variable called LD_LIBRARY_PATH=/root-to-my-libs