CMAKE C Macro not propagating to include directory - c

I have a Open source C library I want to compile but to set the compiler to recognize OpenMPI is have to set the C macro PARALLEL to 1 so that in the header files the:
#ifdef PARALLEL
#include <mpi.h>
#endif
Will execute. Below is the CMAKE file I'm dealing with where it adds the src directory as a subdirectory and the header file as an include_directory.
Using this sets the C macro PARELLEL correctly for everything in the src directory. However, everything in the include directory is left with PARALLEL undefined.
cmake_minimum_required(VERSION 3.14)
project(SDFC VERSION 14.4.2 LANGUAGES C)
option(PARALLEL "Using MPI" ON)
set(TOPLEVEL "${CMAKE_CURRENT_SOURCE_DIR}")
#file(GLOB SOURCE_ALL include/*inc CMakeLists.txt Makefile*)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fpic -g")
if(${CMAKE_C_COMPILER_ID} STREQUAL "GNU")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -gdwarf-2")
endif()
set(SDFC_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include" CACHE PATH
"Path to include files for SDF C library")
set(SDFC_LIB_DIR "${CMAKE_CURRENT_BINARY_DIR}/src" CACHE PATH
"Path to build directory for SDF C library")
include_directories(include)
add_subdirectory(src)
if(PARALLEL)
find_package(MPI REQUIRED)
include_directories(${MPI_C_INCLUDE_PATH})
add_compile_definitions(-DPARALLEL)
#add_compile_definitions(-DPARALLEL)
include(CMake/CheckMPIVersion.cmake)
endif()
install(DIRECTORY include DESTINATION . COMPONENT develop PATTERN uthash.h EXCLUDE)
install(FILES src/uthash/include/uthash.h DESTINATION include COMPONENT develop)
I use:
cmake .
make
Any help is appreciated.

So it turns out that just because a static library is compiled and built using CMAKE which sets the preprocessor macros for header file (say library.h):
#ifdef PARALLEL
#include <mpi.h>
#endif
Doesn't mean you can use the static library and header file in your new code without defining the preprocessor macro.
So after making this static library with:
cmake .
make
I got a library.a file
In order to link it to my new code, say main.c that uses #include "library.h", I had to not only include the library and header file directory in the command line but also had to define the preprocessor macro PARALLEL as follows:
gcc -DPARALLEL=1 -L/Path_To_Library_Directory -I/Path_To_Include_Directory main.c -o main -llibrary

Related

C and MinGW: How do I fix my "No such file or directory" error?

I have made a python "compiler" that helps me compile my C code with gcc, for example it fetches all my header files and source files. So my cmd commmand is gcc {headers} {source} -o {build_dir}/build.exe -lgdi32 -w where {headers} is a string like -Ipath/to/headers/foo.h -Ipath/to/other/headers.foo2.h and where {source} is the same but with .c files. It seems that the compiler finds the header files, but when compiling my code it fails.
(btw I am trying to make a portable programming environment on my flash drive so python and mingw are both portable)
This is the error: fatal error: test.h: No such file or directory #include "test.h"
My project tree
I have put the third party library files into the mingw directory instead of making a custom one and then linking it in the gcc command.
The -I option takes the path to the directory containing the header files or more specifically with an argument -Ipath and a directive #include<a/b.h>, the compiler will try to look for the header file at path/a/b.h.
So you should not give it paths to header files, only to the directory or directories relative to which you use include directives.

Cannot find API header file for shared library with cmake

I am building a shared library in one project and using it in another. They share a prefix, but I'm not building them together (e.g., <prefix>/mylib and <prefix>/myproject). Both mylib and myproject have src and include directories.
The CMakeList.txt for the shared library:
cmake_minimum_required(VERSION 3.5)
project(mylib)
add_library(mylib SHARED
src/mylib.c
)
target_include_directories(mylib PRIVATE include)
set_target_properties(mylib PROPERTIES PUBLIC_HEADER include/mylib.h)
install(TARGETS
mylib
LIBRARY DESTINATION lib
PUBLIC_HEADER DESTINATION include
RUNTIME DESTINATION bin)
This results in mylib.so being installed in install/mylib/lib/mylib.so and mylib.h being installed in install/mylib/include/mylib.h, which is what I intended.
I then want to build a project that uses mylib:
#include "mylib.h"
int main(void)
{
// use some functions in mylib
}
The associated CMakeList.txt file for main.c:
cmake_minimum_required(VERSION 3.5)
project(myproject)
find_package(mylib REQUIRED)
add_executable(myproject src/main.c)
target_link_libraries(myproject mylib)
install(TARGETS
myproject
DESTINATION lib/${PROJECT_NAME})
This produces:
main.c: fatal error: mylib.h: No such file or directory
#include "mylib.h"
^~~~~~~~~
If I change CMakeList.txt to include the following:
find_path(MYLIB_INCLUDE_DIR mylib.h)
...
target_include_directories(myproject PUBLIC ${MYLIB_INCLUDE_DIR})
Then it finds the header, but not the library. I get a linker error:
/usr/bin/ld: cannot find -lmylib
If I change CMakeList.txt to include the following:
find_library(MYLIB_LIB mylib)
...
target_link_libraries(myproject ${MYLIB_LIB})
Then it builds.
I (think I) understand why finding the library and include files manually works, but that seems to be the wrong way to go about things...
find_package(mylib) does seem to find the mylib package (I can print cmake cache variables and mylib_FOUND=1), but doesn't find the library and header in such a way that they are built with myproject.
You need to specify include directories for both "build" and "install" variants in target_include_directories in your library project:
target_include_directories(mylib PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> # build variant
$<INSTALL_INTERFACE:include> # install variant
)
BTW, such example is provided in documentation for target_include_directories command.
Additionally, you need to EXPORT the library during installation:
install(
TARGETS mylib
EXPORT mylib
LIBRARY DESTINATION lib
PUBLIC_HEADER DESTINATION include
RUNTIME DESTINATION bin)
See this answer for a tutorial on exporting libraries with cmake.

How to include header files in external library in CMake

I have a C application which is running on Raspberry Pi 3 and currently, I have to build it on PI with Cmake. I am trying to build it on Ubuntu machine. I have added a CMAKE_TOOLCHAIN_FILE as described here.
I could run cmake. -DCMAKE_TOOLCHAIN_FILE without any problem but the "make" command is not successful and it can not find a header file inside one of the external library: "mirsdrapi-rsp". The error message is:
fatal error: mirsdrapi-rsp.h: No such file or directory
#include "mirsdrapi-rsp.h"
^
compilation terminated.
I have created a folder named "lib" and have put the "libmirsdrapi-rsp.so" file inside it.
my CMakeLists.txt is as below:
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pedantic -Wextra -v -g -D_XOPEN_SOURCE")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -Wextra -v ")
set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} "-v")
set (SDR_API_PATH ${CMAKE_SOURCE_DIR}/lib)
include_directories (include ${SDR_API_PATH})
include_directories("${CMAKE_SOURCE_DIR}/lib")
find_library(mirslocation NAMES mirsdrapi-rsp HINTS ${SDR_API_PATH} NO_CMAKE_FIND_ROOT_PATH)
message(STATUS ${mirslocation})
add_library(mirs STATIC IMPORTED)
set_target_properties(mirs PROPERTIES IMPORTED_LOCATION ${mirslocation})
target_link_libraries (raspberryPiDaemon mirs)
target_link_libraries(raspberryPiDaemon m)
Cmake is printing the right path of the library mirsdrapi-rsp while running "find_library" and as I mentioned I am getting the error message just while running "make" command and not "cmake" command.
My content of CMAKE_TOOLCHAIN_FILE is as below:
# Define our host system
SET(CMAKE_SYSTEM_NAME Linux)
SET(CMAKE_SYSTEM_VERSION 1)
# Define the cross compiler locations
SET(CMAKE_C_COMPILER ${CMAKE_SOURCE_DIR}/../tools-master/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc)
SET(CMAKE_CXX_COMPILER ${CMAKE_SOURCE_DIR}/../tools-master/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc)
# Define the sysroot path for the RaspberryPi distribution in our tools folder
SET(CMAKE_FIND_ROOT_PATH ${CMAKE_SOURCE_DIR}/../tools-master/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/arm-linux-gnueabihf/sysroot/SET)
# Use our definitions for compiler tools
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# Search for libraries and headers in the target directories only
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)
add_definitions(-Wall -std=c11)
Anybody knows how I can add the header file from mirsdrapi-rsp library to include path?
I guess that you're setting include_directories to the wrong path (it is set 2 times to ${CMAKE_SOURCE_DIR}/lib which must be the folder of libraries not the header files). Check again the correct location of the missing header file.
More precisely: you need to find the path of mirsdrapi-rsp.h and let CMake know it just like for find_library:
find_path(MIRSDRAPI_INCLUDE_DIRS NAMES mirsdrapi-rsp.h PATHS {proper-location})
if (MIRSDRAPI_INCLUDE_DIRS)
target_include_directories(raspberryPiDaemon PRIVATE ${MIRSDRAPI_INCLUDE_DIRS})
endif()
In addition, you can set the INTERFACE_INCLUDE_DIRECTORIES property to the library like this:
set_property(TARGET mirsdrapi-rsp APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${MIRSDRAPI_INCLUDE_DIRS})
This way, target_include_directories might be unnecessary and target_link_directories should be enough.

Set up cmakelist correctly to compile project

This is my working directory:
app
|___include
|___file1.h
|___file2.h
|___file3.h
!___ ...
|___src
|___file1.c
|___file2.c
|___file3.c
|___ ...
|__CMakeLists.txt
|__mainapp.c
And this is my CMakeLists.txt:
cmake_minimum_required(VERSION 3.5.1)
project(app)
include_directories(include)
file(GLOB SOURCES src/*.c)
add_executable(file3 src/file3.c)
target_link_libraries(file3 m ${SOURCES})
Then I do the following:
$cmake .
$make
But I get errors:
[ 50%] Building C object CMakeFiles/file3.dir/src/file3.c.o
[100%] Linking C executable file3
src/file3.c:1:19: fatal error: file1.h: File does not exist
Where file3.c is just:
#include "file1.h"
#include "file2.h"
int foo3(int a, int b){
return foo1(a,b) + foo2(a,b);
}
How do I set up CMakeLists correctly?
You are linking source files to your executable but you should compile them.
target_link_libraries(file3 m ${SOURCES})
Normally you put all your source files into the add_executable for compilation and only link libraries like m (libm for math functions).
add_executable(file3 ${SOURCES})
target_link_libraries(file3 m)
This of course only works if none of the other files contain a main function.
Your include_directories(include) is appended to the gcc call as -Iinclude which is used during compilation. https://gcc.gnu.org/onlinedocs/cpp/Include-Syntax.html. You can see your gcc calls with make VERBOSE=1.
During Linking gcc doesn't look there anymore, that's why it tells you it can't find that function (after that it would probably fail elsewhere)
You could also build a library with your sources and link your executable against that. But then don't include file3 in the sources for the library.
Using
#include "file1.h"
searches for file.h in the current directory and not in the other included directories.
Use
#include <file.h>
instead.
Hope this helps

how #Include works when I compile a linux kernel

I need to compile a 2.6.28 linux kernel with arm-linux-gcc as an embeded system.I'm running Ubuntu 12.10 x86.
I viewed the 2.6 kernel source code and found this:
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/input.h>
#include <asm/io.h>
#include <asm/irq.h>
...
Will gcc compiler include these files from /usr/include /usr/local/include or from Linux_2.6.28 source folder?
The Kernel is self-contained. This means that it is not allowed to have any external dependency. In other words, your Kernel source tree contains all the material needed to build your Kernel. There is no point to look for code anywhere else.
As I suggested in my comments, just take a glance at the main Makefile. You'll find it under the root of your source tree. A little ctrl+f with "include" and here's interesting quotes I can feed back to you :
# Look for make include files relative to root of kernel src
MAKEFLAGS += --include-dir=$(srctree)
# .... Other stuff
# Use USERINCLUDE when you must reference the UAPI directories only.
USERINCLUDE := \
-I$(srctree)/arch/$(hdr-arch)/include/uapi \
-Iarch/$(hdr-arch)/include/generated/uapi \
-I$(srctree)/include/uapi \
-Iinclude/generated/uapi \
-include $(srctree)/include/linux/kconfig.h
# Use LINUXINCLUDE when you must reference the include/ directory.
# Needed to be compatible with the O= option
LINUXINCLUDE := \
-I$(srctree)/arch/$(hdr-arch)/include \
-Iarch/$(hdr-arch)/include/generated \
$(if $(KBUILD_SRC), -I$(srctree)/include) \
-Iinclude \
$(USERINCLUDE)
These files should not be directly accessible in the /usr/local etc. If they are, it's a problem, because your kernel will not build correctly unless it uses the ones that belong to that kernel. Some of these files change on a regular basis, as the kernel is being updated and improved.
The files used by the kernel are found in the linux/include/... directory. The compiler options use -nostdinc to avoid the standard include locations from being searched, and then add the appropriate locations from within the kernel source directory.
To find out what files are included for some given compilation, pass -H to gcc.
To add a directory for searching included files, pass -I somedir to gcc, e.g. -I /usr/local/include/; there are preprocessor options to remove directories or to clear the include path.

Resources