Set up cmakelist correctly to compile project - c

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

Related

CMAKE C Macro not propagating to include directory

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

How to link my main.c file with my library .a file?

I am trying to make a static library that belongs to me. Suppose there are two files: stack.h stores the declarations which I want to store it in the ./include document, and stack.c implements the definition, and main.c call the functions in the stack.h.
Make stack.a file which I want to store it in ./libwith those instructions:
>> gcc -c stack.c
>> ar -cq libstack.a stack.o
>> mv stack.h include
>> mv libstack.a lib
If I want to link the main.c with my libstack.a, what I am going to do with gcc? Do I need to put this lib into the PATH? If so, how to do it?
If next step, I want to do my dynamic library .so file, can anyone give some advice?
C Libraries
In general, libraries are created from many library source files and are either built as archive files (libmine.a) that are statically linked into executables that use them, or as shared object files (libmine.so) that are dynamically linked into executables that use them. To link in libraries of these types, use the gcc command line options -L for the path to the library files and -lto link in a library (a .so or a .a):
-L{path to file containing library} -l${library name}
For example, if I have a library named libmine.so in /home/newhall/lib/ then I'd do the following to link it into my program:
$ gcc -o myprog myprog.c -L/home/newhall/lib -lmine
You may also need to specify and include path so the compiler can find the library header file: -I /home/newhall/include
If you create your own shared object files and do not install them in /usr/lib, then you need to set your LD_LIBRARY_PATH environment variable so that the runtime linker can find them and load them at run time.
For example, if I put my .so files in a directory named lib in my home directory, I'd set my LD_LIBRARY_PATH enviroment to the following:
# if running bash:
>> export LD_LIBRARY_PATH=/home/newhall/lib:$LD_LIBRARY_PATH
# if running tcsh:
>> setenv LD_LIBRARY_PATH /home/newhall/lib:$LD_LIBRARY_PATH
USING AND LINKING LIBRARY CODE
To use a Library that is not linked into your program automatically by
the compiler, you need to
include the library's header file in your C source file (test.c in the example below)
tell the compiler to link in the code from the library .o file into your executable file:
step 1: Add an include line (#include "somelib.h") in a program
source file (e.g., test.c).
step 2: Link the program's .c file with the library object file
(i.e. specify the somelib.o file as a command line argument to gcc):
>> gcc -o myprog test.c somelib.o
The resulting executable file (myprog) will contain machine code for all
the functions defined in test.c plus any mylib library functions that are called by.
CREATING AND USING YOUR OWN LIBRARY CODE
To create a Library of code you need to do the following:
(1) Create an INTERFACE to your library: mylib.h
(2) Create an IMPLEMENTATION of your library: mylib.c
(3) Create a LIBRARY OBJECT FILE (.o) that can be linked with programs that use your library
3a. or create a SHARED OBJECT FILE (.so) from many .o files that can be dynamically linked with programs that use your library
3b. or create an ARCHIVE FILE (.a) from many .o files that can be statically linked with programs that use your library
(4) USE the library in other C code: (a) #include "mylib.h" (b) link in the libary code into a.out file
(5) Set LD_LIBRARY_PATH environment variable for finding shared objects in non-standard locations at runtime
Details:
(1) INTERFACE: the header file to your library should contain definitions for everything exported by your library:
function prototypes with comments for users of your library functions
definitions for types and global variables exported by your library
You should have "boiler plate" code (#ifndef ... #endif) around the header file's contents, to ensures that the preprocessor only includes the mylib.h file one time.
Here is what an example .h file might look like:
#ifndef MYLIB_H_ // _MYLIB_H_ is not allowed.
#define MYLIB_H_
// a constant definition exported by library:
#define MAX_FOO 20
// a type definition exported by library:
struct foo_struct {
int x;
float y;
};
typedef struct foo_struct foo_struct;
// a global variable exported by library
// "extern" means that this is not a variable declaration, it
// just defines that a variable named total_foo of type int
// exits and you can use it (its declaration is in some library source file)
extern int total_foo;
// a function prototype for a function exported by library:
extern int foo(float y, float z); // a very bad function name
#endif
(2) IMPLEMENTATION: create a mylib.c file that #includes "mylib.h" and contains the implementation of every function in your library.
#include "mylib.h"
...
int total_foo;
int foo(float y, float z) {
...
}
(3) create a LIBRARY OBJECT FILE that can be linked into other programs that use your library (use the -c option to gcc to tell it just to create an object file (a .o file) rather than an executable:
>> gcc -o mylib.o -c mylib.c
you can then use the mylib.o file as the "library file" and statically link it into other programs that use it, or...
(3a) alternately, you can create a SHARED OBJECT FILE from one or more .o files that can be linked into other programs that use your library A shared object file is the Unix name for a dynamically linked library whose code is loaded into the a.out file at runtime. To create a .so file use the -shared flag to gcc. Here is what an example build might look like:
>> gcc -shared -o libmylib.so mylib.o blah.o grr.o -lm
(3b) you could also build an ARCHIVE FILE (a statically linked library, libmylib.a) from one or more .o files. If you link with a static library, its code is copied into the a.out file at runtime.
See gcc documentation for more information on how to build .a and .so files.
(4) USE the library in other programs:
step 1: Add an include line (#include "mylib.h") in all program source files that use library definitions (e.g., test.c).
step 2: Link the program's .c file with the library object file
(i.e. specify the mylib.o file as a command line argument to gcc):
gcc test.c mylib.o
OR to link in libmylib.so (or libmylib.a):
gcc test.c -lmylib
OR to link with a library not in the standard path:
gcc test.c -L/home/newhall/lib -lmylib
The resulting a.out out will contain machine code for all the functions
defined in test.c plus any mylib library functions that are called by
the test.c code.
(5) RUNNING an executable linked with a shared object file:
If the shared object file in not in /usr/lib, then you need to set your
LD_LIBRARY_PATH environment variable so that the runtime linker can find
and load your .so file into the executable at runtime:
in bash:
>> export LD_LIBRARY_PATH=/home/newhall/lib:$LD_LIBRARY_PATH
in tcsh:
>> setenv LD_LIBRARY_PATH /home/newhall/lib:$LD_LIBRARY_PATH
there is another useful link: demo for making libraries

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.

C include error multiple definition error

I'm encountering a classic error but still don't get why it occurs...
Below is the simplified explanation
Apparently I have two C files main.c and support.c
in support.c i have one function void bla(int input);
in main.c i have several functions using bla from support.c, and i included
#include<support.c>
at the top of main.c
However I cannot compile the project because of the error multiple definition of bla, first defined here (eclipse points to the definition of bla in support.c)
I know that optimally I would have to create header file support.h and gives prototype extern void bla(int input) there, but for this I have to include the .c file.
Thanks in advance.
The preprocessor will copy the contents of support.c, and paste it to main.c to replace the line #include<support.c>. So there are two definition of the function bla, one in support.c, the other in main.c.
The solution is, don't include an source file. Put the declarations of functions that you want to export in a header file support.h, and include the header file in main.c:
#include "support.h"
You don't include source files into other source files. Instead you make a header file (with the extension .h) that contains declarations of functions, i.e. function prototypes. Then you build both source files separately, and link them together to form the final executable.
So a header file support.h like
#ifndef SUPPORT_H
#define SUPPORT_H
void blah(void);
#endif
(The preprocessor #ifdef/#define/#endif things are for include guards, to protect from multiple inclusion in the same source file.)
Then the support.c source file
#include "support.h"
void blah(void)
{
/* Some code here... */
}
And finally the main.c source file
#include "support.h"
int main(void)
{
blah();
return 0;
}
If you have an IDE (like Visual Studio) if you add these files to your project the IDE will make sure everything is built and linked properly. If you're compiling on the command line, compile each source file into an object file (usually using an option like -c (used for GCC and clang)) and then link the two object files together to create the executable.
Command line example with GCC:
$ gcc -Wall -c main.c -o main.o
$ gcc -Wall -c support.c -o support.o
$ gcc main.o support.o -o my_program
The above three commands will first compile the source files into object files, and then link them together.
What compiler are you using?
When compiling, make sure you do this:
gcc main.c support.c -o yourProgram

Cgo include archive .a file

I'm trying to use an external C library with my Go program.
I have tried the following:
package cgoexample
/*
#include <stdio.h>
#include <stdlib.h>
#cgo CFLAGS: -I/Users/me/somelib/include
#cgo LDFLAGS: /Users/me/somelib/libhello.a
#include "stinger.h"
void myprint(char* s) {
printf("%s", s);
}
*/
import "C"
import "unsafe"
//... more here
In the /Users/me/somelib/include there is the .h file and in libhello.a there is the .o file (I checked using the ar command) that has the defined functions that are in the .h file.
It seems that the .h files are being linked OK, but it doesn't look like the archive file is being linked. I keep getting these:
warning: 'some_method_in_my_h_file" declared 'static' but never defined
And these warnings are being treated as errors. Regardless, they should be implemented in the archive file, so I'm confused what I'm doing wrong here.
When I run go build and gun run.
I have a feeling my #cgo command is invalid (I'm not C expert),
Right, it doesn't work with ar object archives (*.a). There are two things you can do:
Link it in as a shared library (-lfoo in LDFLAGS, with libfoo.so in the library search path)
Put the *.c files themselves within the Go package directory, so that go build builds and links them in
If you're willing to go out of the standard go build behavior, though, you can unpack the *.a file into the individual object files, and then mimic the behavior of go build and cgo by hand.
For example, if you build a trivial cgo sample package with the -x option, you should see output similar to this:
% go build -x
(...)
.../cgo (...) sample.go
(...)
gcc -I . -g (...) -o $WORK/.../_obj/sample.o -c ./sample.c
(...)
gcc -I . -g (...) -o $WORK/.../_obj/_all.o (...) $WORK/.../_obj/sample.o
(...)
.../pack grcP $WORK $WORK/.../sample.a (...) .../_obj/_all.o
cd .
.../6l -o $WORK/.../a.out (...) $WORK/.../sample.a
(...)
So you can see that the individual *.c files are being compiled by gcc, packed together into a Go-specific ar archive, and then linked by 6l. You can do these steps by hand as well, if for some reason you really cannot put the *.c files in the package directory and let go build handle them for you (which would be a lot simpler and give people the chance of go geting your package).

Resources