cmake subdirectories fortran Project - cmake

I have a project developed under FORTRAN. To organize the project I have decomposed it in subdirectories. Then, I would use Cmake files to generate Makefiles.
The hierarchy of the project is:
Main_directory
|____lib
|____inc
|____src
|__src1
|__src2
|__src3
|____tests
|___test1.f90
|___test2.f90
The lib directory content compiled static lib files (. a), Inc contain include files (. h), and src content Fortran source files. Thus, source files in src folder depend between them during compilation, and file in src2 can use variables or function, from file in src1 and uses also lib and include files. Since, the source files in the source directory (src) are compiled they will be used by a source file(test1.f90 or test2.f90) that generate executable in test directory.
I'm newbie with Cmake so I would like to know how to write Cmake files for the main folder and subdirectories.
thank you.

Related

Install a target defined in an included directory [duplicate]

Consider the following CMakeLists.txt file:
add_subdirectory(execA)
add_subdirectory(libB)
install(TARGETS execA libB
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
I get the following error:
install TARGETS given target "execA" which does not exist in this
directory
execA and libB have their own CMakeList.txt files and are located under project directory, as well as the build directory I'm running cmake (cmake ..):
project
|------ CMakeList.txt (the one with the code)
|----execA
| \- .cpp, .hpp and CMakelist.txt
|----libB
| \- .cpp, .hpp and CMakelist.txt
|---- lib
|---- bin
\---- build (where I´m commanding: $ cmake ..
How do I fix this error?
According to this bugreport, install(TARGETS) command flow accepts only targets created within the same directory.
So you need either move the add_library() call into the top-level directory, or split install(TARGETS) call into per-target ones, and move each of them into the corresponding subdirectory.
Since CMake 3.13 install(TARGETS) can work even with targets created in other directories.
install(TARGETS) can install targets that were created in other directories. When using such cross-directory install rules, running make install (or similar) from a subdirectory will not guarantee that targets from other directories are up-to-date.
Even though it would help seeing the CMakeLists.txt files contained in the subdirectories, I guess they contain add_executable and/or add_library statements to create your stuff.
Also, because of your example, I guess you are using the same name of your directories for your targets.
That said, you should know that symbols defined in a CMakeLists.txt file in a subdirectory are not visible by default within the context of the CMakeLists.txt file in the parent directory. Because of that, you should rather move your install statements within the CMakeLists.txt files within your subdirectories.
This should solve the problem, if my thoughts were right. Otherwise, I strongly suggest you to post in your question also the content of the other files above mentioned.
Anyway, the error is quite clear.
The file that contains the install statement for the target named X does not contain a target creation statement (add_executable and the others) that gives birth to that target, so it goes on saying that that target does not exist in that directory.
This still seems to be a pain point in CMake 3.11.
In our codebase, we have many targets defined in subdirectories and need to create an assortment of installers with different configurations and (potentially overlapping) combinations of targets.
Here's my solution:
Before calling add_subdirectory in your root CMakeLists.txt file, create a GLOBAL property with the names of the target(s) you want to include in your installer.
Wrap target creation functions (add_executable, etc.) in your own custom functions. Within those functions check if the target is present in the global property, and invoke install accordingly.
That approach allows you to centralize installer configuration.
Also: To support creation of multiple installers, we populate our global list along with other installer properties in separate .cmake files. When we invoke cmake, we pass the name of the installer configuration CMake file as a command-line argument. Our root CMakeLists.txt file simply calls include with that file.

Set output directory for CMake OBJECT libraries

In my CMake file I've specified an object library:
add_library(core OBJECT ${sourcefiles})
I refer to this set of object file in a shared library further on:
add_library(sharedlib SHARED $<TARGET_OBJECTS:core>)
This works fine, however I would like to reuse the build artefacts between different project.
By setting the LIBRARY_OUTPUT_PROPERTY on the sharedlib I can direct the generated .so file to a common directory:
set_target_properties(sharedlib PROPERTIES LIBRARY_OUTPUT_NAME /commondir)
However, I cannot seem to do the same thing for the core (OBJECT) library - the .o files always end up in the (project-specific) generated cmake-build directories.
This means every project will have to rebuild the (large) shared library anyway...
Am I doing something wrong, or is this not (yet?) possible with CMake?
You can't change the output directory of object/intermediate files in CMake. That's by design (to allow several identical output names in one project):
"There is no way to change that name.
CMake creates an exact copy of the source tree in
the binary tree."
But with version 3.9 CMake learned to export object libraries:
cmake_minimum_required(VERSION 3.9)
project(CorePorject)
file(WRITE "core.cpp" "")
file(WRITE "helper.cpp" "")
set(sourcefiles "core.cpp" "helper.cpp")
add_library(core OBJECT ${sourcefiles})
export(
TARGETS core
FILE core.cmake
NAMESPACE Core_
)
References
Set C++ object file output location with CMake
Set the directory for Intermediate files (like .obj) in CMake
Making cmake library accessible by other cmake packages automatically

cmake "exporting" shared library on windows

I'm writing a small library.
I'd like to build it as shared library and generate "MyLibraryConfig.cmake" file which then can be used by my other projects to find my library.
The only problem I have is to figure out the name/path to file which is used for linking under Windows - there are two files being generated: mylibrary.dll and mylibrary.dll.a.
So I'd like to generate MyLibraryConfig.cmake file with something like:
"set(MYLIBRARY_LIBRARIES /blah/blah/mylibrary.dll.a)"
so then MYLIBRARY_LIBRARIES can be used with target_link_libraries for my other projects.
How can I get name for this linkable file? I'd be nice if the solution was platform independed (returning .so wile on Linux and .dll.a on Windows)
thanks in advance
If you're planning on making your library available to your other projects without installing it then you want the CMake command export. For example:
export(TARGETS MyLib FILE ${CMAKE_SOURCE_DIR}/MyLibraryConfig.cmake)
This creates the file MyLibraryConfig.cmake in the same directory as your top-level CMakeLists.txt, and can just be included in other CMake projects.
If you're planning on installing your library, then you want to make use of install(EXPORT ...) instead:
install(TARGETS MyLib EXPORT MyLibraryConfig
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib/static)
install(EXPORT MyLibraryConfig DESTINATION cmake)
This will install the file MyLibraryConfig.cmake to <install path>/cmake, and can then be included by other projects.

Naming CMake Targets by directory

I am new to CMake and am having a bit of trouble. Is it possible to name CMake targets according to the directory they were created in? For instance, I would like to write my libraries to a lib/ directory that would echo my source directory structure.
Imagine i have source directories dir1 and dir2, and both create a library libmylib.a Normally CMake might complain about creating libraries/targets with the same name, but if the libraries were written to lib/dir1/libmylib.a and lib/dir2/libmylib.a then you could reference these targets as dir1/libmylib and dir2/libmylib in your CMakeLists.txt files (presumably) without conflict.
In CMake, logical library name can be totally decoupled from the name of the file produced by the target. There is no problem in having a / in your target names. You could add your libraries like this:
add_library(dir1/mylib STATIC source1 source2 ...)
set_property(TARGET dir1/mylib PROPERTY OUTPUT_NAME mylib)

Moving Headers/Libraries/Executables to specific directories

I've recently started using CMake for one of my multi-platform projects, but I'm having a little trouble figuring out how to do something.
Basically, inside the project I've got multiple libraries and executables, all in their own folders. I would like to place all of the compiled libraries into one directory on build i.e. a lib folder inside the CMake build folder. I would like to do the same things for the executables.
CMake Build Directory
| ----------> bin (where i want the executables to go)
| ----------> lib (where i want the libraries to go)
| ----------> utils (where the libraries are ordinarily compiled)
| ----------> test (where the executables are ordinarily compiled)
There are directories inside utils and apps for all the different libraries and executables I'm making. I have a CMakeLists in the base folder of my source directory which adds all the subdirectories. If anything does not make sense then feel free to ask.
You can also use this:
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin )
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
Look at install CMake command.
Here example from that page:
install(TARGETS myExe mySharedLib myStaticLib
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib/static)
install(TARGETS mySharedLib DESTINATION /some/full/path)
So you can use CMAKE_BINARY_DIR instead /some/full/path
In addition, for includes:
install( FILES ${HEADERS}
DESTINATION inc )
[when set of header files to be installed]
install( DIRECTORY include/${PROJECT_NAME}/
DESTINATION inc)
[when header directory to be installed]
More Info