Converting a makefile to cmake using caching of .h files [duplicate] - c++

Question is similar to this question
Handling header files dependencies with cmake
I have sample program dir having main.c main.h and CMakeLists.txt
main.h contents are
#ifndef MAIN_H
#define MAIN_H
int t=3;
int y=2;
#endif
main.c contents are
#include <main.h>
#include<stdio.h>
int main(){
printf("%d apple",t);
}
and CMakeLists.txt
PROJECT( test )
AUX_SOURCE_DIRECTORY(. test_SRCS)
include_directories(.)
ADD_EXECUTABLE (main ${test_SRCS})
but cmake is not rebuilding main.c on modification of header file.
I want it to auto-generate header file dependency.
Is it possible using cmake ?
if not is there any other tool which can do that ?

As mentioned in my comment, I have tried out your example and things were working fine: if main.h was modified then main.c would be recompiled.
My installation of CMake (version 2.8.0) told me to add
cmake_minimum_required(VERSION 2.8)
to the CMakeLists.txt file, but that is all of the adjustments I needed.

Answering this for others that google search...
I ran into this problem with one of my projects. As it turns out I added the header to the cpp file after running cmake. Re-running cmake fixed the problem. If you run into this, try that and see if it fixes the issue.

From the cmake 2.8.0 documentation of AUX_SOURCE_DIRECTORY:
It is tempting to use this command to avoid writing the list of source
files for a library or executable target. While this seems to work,
there is no way for CMake to generate a build system that knows when a
new source file has been added. Normally the generated build system
knows when it needs to rerun CMake because the CMakeLists.txt file is
modified to add a new source. When the source is just added to the
directory without modifying this file, one would have to manually
rerun CMake to generate a build system incorporating the new file.
Why do you want to avoid creating a list of files? Such lists generally do not change frequently.

Related

C++ - Why is a Static Library unusable without source files?

So from what I understand, a static compiled mylib.a file should just be usable as plug-and-play. But I can't use it without the source code, I'm trying to avoid that.
I adapted this tutorial to compile using CMake with the following directory structure:
/
lib
libmy_math.a
main.cpp
my_math.h
my_math.cpp
CMakeLists.txt
The contents of the files are exactly as in the tutorial. The only added file is CMakeLists.txt which basically just runs the library compiling part before building:
CMakeLists.txt
cmake_minimum_required(VERSION 3.21)
project(Test)
### Uncomment this ONCE to compile a libmy_math.a file
# add_library(my_math STATIC my_math.cpp)
add_executable(Test main.cpp)
find_library(MY_MATH_LIB my_math HINTS ./lib)
target_link_libraries(Test PUBLIC ${MY_MATH_LIB})
As the CMake file says, uncommenting Line 5 compiles the library, which is then linked to my code when compiling.
I'm trying to package my code so that I don't show my client the source code for the compiled library (my_math), but if I delete the my_math.h and my_math.cpp files, I get a "file not found" error on import:
/Users/Joe/Desktop/Test/main.cpp:1:10: fatal error: 'my_math.h' file not found
#include "my_math.h"
^~~~~~~~~~~
I thought you could compile libraries without needing the source code. What am I missing here?
A static library does not contain each and every definition a header can contain - think of macros, etc. Thus you still need the header. However, you don't need the .cpp anymore to link the library.
Besides the problem stated in Iorro's answer the find_library call here will not work as expected.
find_library(MY_MATH_LIB my_math HINTS ./lib)
target_link_libraries(Test PUBLIC ${MY_MATH_LIB})
What this does is, while running CMake, look for the my_math.a file. However, at that point of the build process, my_math.a has not been built yet. You're just running CMake for the first time, so all you have is source files. Nothing has been compiled yet.
What you want to do instead is link to the library target directly, as CMake already knows about that and can resolve the dependency on its own. So you need to replace the two lines above with:
target_link_libraries(Test PUBLIC my_math)
This now introduces a curious asymmetry in how your test consumes the library (as it is part of the same build) vs. how your clients consume the same library (which are not part of the same build and thus need to do a find_package call before they can use it). Look at CMake's config-file packages for a mechanism that allows you to restore symmetry here, at the cost of a significant amount of boilerplate required in your CMake script.

how to write the cmakelist for multi-static library in same parent

I'm newer to the cmake, I'm currently working with the project that builded with cmake, I'm now known how to write the cmakelist for static library.Nonetheless, I cannot know how to write cmakelist for the following section:
|---TopLevel
|--->StaticLib
|----->CMakeLists.txt #1
|----->LIB1
|------->myadd.h
|------->myadd.cpp
|------->CMakeLists.txt
|----->LIB2
|------->mysub.h
|------->mysub.cpp
|------->CMakeLists.txt
|---main.cpp
|--->CMakeLists
I'm know how to write all cmakelists other than the comment #1(I'm not definitely insure that these cmakelists I wrote are prefertly proper).
Additional, there are some functionals in Lib1 were used in Lib2. When I attemp to include the mysub.h in main, the compiler give the warning cannot open myadd.h, how to resolve this problem.
//in mysub.h
#ifndef MY_SUB__HPP
#define MY_SUB__HPP
include "myadd.h"
#endif
thanks everyone
By using add_subdirectory(<subdirectoryName>), with CMakeLists.txt in those subdirectories defining their own targets.
Sorry that I am with no enough reputation to put it as a comment, which I think is more suitable.

Compile app with linked dll with CMake. Need to see a working sample

Answer is found. To save your time from reading alot:
Useful Document Here:
https://gitlab.kitware.com/cmake/community/-/wikis/doc/tutorials/Exporting-and-Importing-Targets
The working CMakeLists.txt is like this:
cmake_minimum_required(VERSION 3.10)
project(Test VERSION 1.0)
add_library(Lib SHARED IMPORTED)
set_property(TARGET Lib PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/lib.dll")
set_property(TARGET Lib PROPERTY IMPORTED_IMPLIB "${PROJECT_SOURCE_DIR}/lib.dll.a") //Notice: lib.lib here if you are using VS building system.
add_executable(App app.cxx)
target_link_libraries(App Lib)
Most tutorial online will assume you are using MS VS build system. Thus they will keep talking about importing a "*.lib" file.
If you use GCC(MinGW) like me, the actually file you are looking for is "*.dll.a"
Edit in Sep.17
No it's not right. We are using a DLL. And a DLL should not affect the compiling.
DLL should be whenever you want to place them into the folder which the .exe required instead of compiling check for header.
But we are trying to unpack a header from a dll.
There must be something wrong with this workflow.
CMake and GCC
I cannot use any IDE nor VS Build Tool due to the lack of license in my company.
Thus I'll have to learn about CMake + GCC for an open-sourced compile environment.
I could compile app and static library correctly now. But stuck in dll linkage.
This should be a simple one but since I can't find any sample on Google thus I need your help to correction the CMake workflow in this DLL linking job. Thanks.
Or maybe any hyperlink where could find a right direction.
As I know, I could simply add the dll library in IDE like VisualStudio and it will do all the magic to exchange it into something containing a header file.
I must missed this part in CMake.
My Step:
Compile a dll
Compile an legacy app without dll
Recreate the app with function linked from dll (BOOM!)
Detailed codes below:
Step 1: Compile a dll
Code in Test.h:
#pragma once
#ifdef TEST_EXPORTS
#define TEST_API __declspec(dllexport)
#else
#define TEST_API __declspec(dllimport)
#endif
extern "C" TEST_API int helloworld();
Code in Test.cxx:
#include <iostream>
#include "Test.h"
int helloworld() {
std::cout << "I hate HelloWorld\n";
return 0;
}
Code in CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)
project(Test)
include(GenerateExportHeader)
add_library(Test SHARED Test.cxx)
generate_export_header(Test)
Compile it. Get a "libTest.dll". Good.
Step 2: Compile a legacy app without a dll
Let's skip it. Just a hello world console app. Nothing special.
Compile finished. Good to go.
Step 3: Recreate the app with linked dll
I've tried so many sample from google but no luck till now.
I've tried the library's name both "Test" and "libTest".
I've tried to put the dll directly in both ${PROJECT_BINARY_DIR}, ${PROJECT_SOURCE_DIR}, and make an add_subdirectory(libStore).
I've tried to use find_package(Test/libTest).
Thus I think there should be something incorrect in my cmake and source code.
Code in App.cxx:
#include <iostream>
#include "Test.h" //Also tried "libTest.h"
int main() {
std::cout << helloworld();
getchar();
return 0;
}
Attempt 1:
Put libTest.dll under sub directory "/Lib"
Code in root CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)
project(App VERSION 1.0)
include_directories("${PROJECT_SOURCE_DIR}/Lib")
add_subdirecotry(Lib)
add_executable(App App.cxx)
target_link_libraries(App libTest) //Tried both Test and libTest
Code in /Lib CMakeLists.txt:
add_library(libTest libTest.dll)
set_target_properties(libTest PROPERTIES LINKER_LANGUAGE C)
Build result:
Fatal Error: Test.h(libTest.h): No such file or directory.
Attempt 2:
Put libTest.dll directly in source directory (${PROJECT_SOURCE_DIR})
Code in CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)
project(App VERSION 1.0)
include_directories("${PROJECT_SOURCE_DIR}")
add_executable(App App.cxx)
target_link_libraries(App libTest) //Tried both Test and libTest
Build Result:
Fatal Error: Test.h(libTest.h): No such file or directory.
Attempt 3:
Same with Attempt 2 but add a find_package(libTest) function.
cmake_minimum_required(VERSION 3.10)
project(App VERSION 1.0)
include_directories("${PROJECT_SOURCE_DIR}")
find_package(libTest)
add_executable(App App.cxx)
target_link_libraries(App libTest) //Tried both Test and libTest
CMake Warning:
Could not find a package configuration file provided by "libTest" with any of the following names:
libTestConfig.cmake
libTest-config.cmake
Created an empty file names libTestConfig.cmake in source directory.
Build Result:
Fatal Error: Test.h(libTest.h): No such file or directory.
BOOM!
At last, I found the answer here:
https://gitlab.kitware.com/cmake/community/-/wikis/doc/tutorials/Exporting-and-Importing-Targets
First:
All of the code in my old attempts are assuming you have your source code in your project folder.
If you want to import a DLL you get from outside, the actually CMakeLists.txt should look like this:
cmake_minimum_required(VERSION 3.10)
project(Test VERSION 1.0)
add_library(Lib SHARED IMPORTED)
set_property(TARGET Lib PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/lib.dll")
set_property(TARGET Lib PROPERTY IMPORTED_IMPLIB "${PROJECT_SOURCE_DIR}/lib.dll.a") //Notice: lib.lib here if you are using VS building system.
add_executable(App app.cxx)
target_link_libraries(App Lib)
Second:
Almost all the tutorial online will assume you are using MS VS build system. Thus they will keep talking about importing a "*.lib" file.
Which will be a big mislead and makes you meaninglessly tracing the non-exist lib file and confuse it with the dll file itself.
If you use GCC(MinGW) like me, the actually file you are looking for is "lib.dll.a"
I think the problem may be here:
include_directories("${PROJECT_SOURCE_DIR}")
Rather than having an issue finding the DLL itself, it seems like cmake is simply having an issue finding the Test.h (or libTest.h) header file. Try putting the DLL's header file in a path that's specified via cmake's "include_directories".

How to add opendnp3 as a static C++ library

I am currently trying to set up the opendnp3 C++ library as a static library. I've built the solution following their build guide for Windows and have been able to generate several .lib files which I assume to be the static libraries.
In a completely separate folder, I have the following files under the following folder structure:
C:/Development/C++/opendnp3/lib/ # .lib files are contained in this directory
C:/Development/pybexample/
--> CMakeLists.txt
--> src/
--> test.cpp
I have the CMakeLists.txt configured as follows:
cmake_minimum_required(VERSION 2.8)
project(pybexample)
set(SOURCE_FILES src/test.cpp)
add_library(opendnp3 STATIC IMPORTED)
set_target_properties(opendnp3 PROPERTIES IMPORTED_LOCATION C:/Development/C++/opendnp3/lib/opendnp3.lib)
add_executable(pybexample ${SOURCE_FILES})
target_link_libraries(pybexample opendnp3)
Within test.cpp, I am simply calling:
#include <iostream>
#include "opendnp3/LogLevels.h"
using namespace std;
int main(void) {
cout << "Hello world!" << endl;
system("pause");
}
However, when I try to build test.cpp, I receive an error indicating: "Cannot open include file: 'opendnp3/LogLevels.h': No such file or directory". I feel like there must be something pretty basic that I've missed but I'm pretty new to using static libraries and with CMake so I can't seem to figure it out. Would anyone be able to help give some pointers as to why my include is failing?
Turns out this was caused by two problems.
The first problem was that I needed to add a line to my CMakeLists.txt that would add the header files for opendnp3 to my project. This was accomplished by adding include_directories(<path_to_headers>) before the add_executable(pybexample ${SOURCE_FILES}) line.
However, in doing this, it also became clear that there was a second problem: I hadn't built the library properly as it didn't generate any headers with the library. Turns out I had overlooked the instructions to run the INSTALL project. After setting CMAKE_INSTALL_PREFIX and running the INSTALL project, the library and headers were generated and ready for use.

In CLion, header only library: file "does not belong to any project target, code insight features might not work properly"

I have a header-only library project set up with the cmake command:
add_library(my_library INTERFACE)
and I also added
target_sources(my_library INTERFACE ${MY_LIRBARY_HEADER_FILES})
but when I open a source file, I get the warning:
This file does not belong to any project target, code insight features might not work properly
and I lose a lot of the functionality on things like code completion.
What is the proper way to set this up so CLion provides its usual functionality on a header-only library?
Little background
I was having the same problem, albeit the project was not header-only, nevertheless, the open files from inc folder were throwing the aforementioned warning, even though the CMake file clearly marked that folder to be include_directory.
*.hpp files do not belong to ${SOURCE}
include_directories("${PROJECT_SOURCE_DIR}/inc/")
add_subdirectory(src)
add_executable(${EXECUTABLE_NAME} main.cpp ${SOURCE})
Since this is a perfectly valid CMake file and adding the include files to source files is not idiomatic, I did not want to amend the CMake file.
The solution
As described on the official JetBrains Forum, the CMake file is indeed valid and the warning is shown because of the inability of CLion to properly index header files. The suggested workaround extracted from the link is to right-click the folder and Mark directory as | Library Files/Project Sources and Headers.
So, this header isn't includes in executables and CLion notifies you that some code insight features might not work properly. As workaround you can use "Mark directory as" Library Files/Project Source and Headers for folder.
Clion takes information about source files from CMake build system. When you add any cpp file to sources list CMake automatically tell about header with same name. So if cpp/h names differs (or you don't have cpp file at all) you should include header manually.
set(Sources my_lib.cpp)
set(Headers header_of_my_lib.h)
add_executable(superlib ${Sources} ${Headers})
If you don't have any executable you can omit last line, CLion will still know about files
This warning is an IDE issue that Android Studio cannot recognise the current directory if it does not include any source files.
Workaround
Adding am empty source file, e.g empty_xxx.c under the directory in question and adding below line in your corresponding CMakeList.txt
add_library(${TARGET_NAME_XXX} SHARED ${SOME_DIR_HAVING_THIS_WARNING}/empty_xxx.c)
will help get rid of this warning.
You can add the header files to your project like this:
set(SOURCE_FILES main.cpp MyClass1.cpp MyClass1.h MyClass2.cpp MyClass2.h)
You can also set it in multiple steps like so:
set(SOURCE_FILES main.cpp)
set(SOURCE_FILES ${SOURCE_FILES} MyClass1.cpp MyClass1.h)
set(SOURCE_FILES ${SOURCE_FILES} MyClass2.cpp MyClass2.h)
Though as mentioned in the comments, you probably shouldn't be adding the header files to your project at all.