I came across this problem and was trying to figure out the best solution.
I am currently working on a library called lib1.h and making some changes to it. I don't want to modify the original file directly so I made a copy and named it lib2.h.
All declaration and definitions are coded in lib1.h and lib2.h, lib1.c and lib2.c, respectively. The code looks like this:
/* lib1.h */
#ifndef LIB1_H
#define LIB1_H
int method1();
int method2();
...
#endif
/* lib2.h */
#ifndef LIB2_H
#define LIB2_H
int method1();
int method2();
...
#endif
/* lib1.c */
#include "lib1.h"
int method1()
{
// old implementation
};
int method2()
{
// old implementation
};
...
/* lib2.c */
#include "lib2.h"
int method1()
{
// new implementation
};
int method2()
{
// new implementation
};
...
Since I am not changing the names of all functions, I am getting multiple definition errors. My current solution is to move the original library out of the current directory and do a make clean and then compile. While this solution works for me, I am just curious if there is any way to keep the two header files in the same directory, or what is a better workflow.
I'd appreciate any pointers.
Multiple definitions is a linker error, not compilation error. Why do you link both libraries? I guess you need only the newer (fixed) one.
There are a few solutions:
Delete the old code,
Put #ifdef 0 on the old code, or move it to separate directory
Use -DNEW_CODE flag in make file and use #ifndef NEW_CODE in old library and #ifdef NEW_CODE in new library. You can quickly switch between versions by editing compilation flags
Just dont include the older version in your make file. Even if you compile it, dont link it.
If you need both versions of library (to compare results?) use prefix to functions or compile as C++ and wrap the functions in name spaces
Use macro hacks to automatically add prefix or suffix to function names. Really dont recommend this approach.
Use source control, like git, and change the library in place, and maintain only 1 copy. you can always revert your commits to get the previos version
Related
I'm working on a project which requires to develop the firmware for several esp32. All the microcontrollers share a common code that takes care of wifi and mqtt, however they all have a different behavior, which is defined in a specific component. The structure of my project is something like this:
- CMakeLists.txt
- Makefile
- sdkconfig
- main
- CMakeLists.txt
- main.c
- components
- wifi_fsm
- wifi_fsm.h
- wifi_fsm.c
- CMakeLists.txt
- mqtt_fsm
- mqtt_fsm.h
- mqtt_fsm.c
- CMakeLists.txt
- entity_1
- entity_1.h
- entity_1.c
- CMakeLists.txt
- entity2
- entity2.h
- entity2.c
- CMakeLists.txt
...
Each entity defines some functions with standard names, which implement specific logic for the entity itself and which are called within the shared code (main, wifi_fsm, mqtt_fsm).
void init_entity(); // called in main.c
void http_get(char *buf); // called in wifi_fsm
void http_put(char *buf);
void mqtt_msg_read(char *buf); // called in mqtt_fsm
void mqtt_msg_write(char *buf);
My idea was to have a conditional statement to include at will a specific behavior, so that depending on the entity included, the compiler would link the calls to the functions above to those found in the specific included library. Therefore, at the beginning of main.c I just added the following lines with the goal of having to change the only defined pre-processor symbol to compile for different enity behaviors.
#define ENTITY_1
#ifdef ENTITY_1
#include "entity_1.h"
#elif defined ENTITY_2
#include "entity_2.h"
#elif ...
#endif
#include "wifi_fsm.h"
#include "mqtt_fsm.h"
void app_main(void)
{
while(1){
...
}
}
On the one hand the compiler apparently works fine, giving successful compilation without errors or warnings, meaning that the include chain works correctlty otherwise a duplicate name error for the standard functions would be thrown. On the other hand, it always links against the first entity in alphabetical order, executing for instance the code included in the init_entity() of the component entity_1. If I rename the standard functions in entity_1, then it links against entity_2.
I can potentially use pointers to standard calls to be linked to specific functions in each entity if the approach above is wrong, but I would like to understand first what is wrong in my approach.
EDIT in response to Bodo's request (content of the CMakeFile.txt)
Project:
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(proj)
Main:
set(COMPONENT_REQUIRES )
set(COMPONENT_PRIV_REQUIRES )
set(COMPONENT_SRCS "main.c")
set(COMPONENT_ADD_INCLUDEDIRS "")
register_component()
Component:
set(COMPONENT_SRCDIRS "src")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_REQUIRES log freertos driver nvs_flash esp_http_server mqtt)
register_component()
This answer is based on guessing because I don't have enough information. For the same reason it is incomplete in some parts or may not fully match the use case of the question.
The details about how the project will be built seems to be hidden in a cmake include file like project.cmake or nested include files.
My guess is that the build system creates libraries from the source code of every individual component and then links the main object file with the libraries. In this case, the linker will find a symbol like init_entity in the first library that fulfills the dependency. This means the library (=component) listed first in the linker command line will be used.
If the linker command line would explicitly list the object files entity_1.o and entity_2.o, I would expect an error message about a duplicate symbol init_entity.
I can propose two ways to solve the problem:
Make sure only the selected entity is used to build the program.
Make the identifier names unique in all entities and use preprocessor macros to choose the right one depending on the selected entity.
For the first approach you can use conditionals in CMakeLists.txt. See https://stackoverflow.com/a/15212881/10622916 for an example. Maybe the register_component() is responsible for adding the component to the build. In this case you could wrap this in a condition.
BUT modifying the CMakeLists.txt might be wrong if the files are generated automatically.
For the second approach you should rename the identifiers in the entities to make them unique. The corresponding header files can define a macro to replace the common name intended for the identifier with the specific identifier of the selected entity.
In the code that uses the selected entity you will always use the common name, not the individual names.
Example:
entity_1.c:
#include "entity_1.h"
void init_entity_1(void)
{
}
entity_2.c:
#include "entity_2.h"
void init_entity_2(void)
{
}
entity_1.h:
void init_entity_1(void);
// This replaces the token/identifier "init_entity" with "init_entity_1" in subsequent source lines
#define init_entity init_entity_1
// or depending on the parameter list something like
// #define init_entity() init_entity_1()
// #define init_entity(x,y,z) init_entity_1(y,x,z)
entity_2.h:
void init_entity_2(void);
#define init_entity init_entity_2
main.c
#define ENTITY_1
#ifdef ENTITY_1
#include "entity_1.h"
#elif defined ENTITY_2
#include "entity_2.h"
#elif ...
#endif
void some_function(void)
{
init_entity();
}
In this example case with #define ENTITY_1, the preprocessor will change some_function to
void some_function(void)
{
init_entity_1();
}
before the compilation step and the linker will use init_entity_1 from entity_1.c. An optimizing linker may then omit the object file entity_2.o or the corresponding library because it is unused.
I am working on a program that is using libgit2. I had kept the code in a single c file. Say:
somefile.c
I compile and use it. Now I want to separate some of the details related to libgit2 into a separate library inside the project. So I created an h file with the data structures that I need and the definitions of the functions I want to use. So far, nothing fancy: init stuff, pass in the path to the repo and s a treeish... those are const * constant.... then In the library c file I have an implementation of the functions in the .h file.
Currently, the layout is like this:
include/mylib.c
include/mylib.h
somefile.c
In include/mylib.h I have one struct and a couple of functions:
struct blah {} blah_info;
int blah_init(cont char * path, const char * treeish);
int blah_shutdown();
In include/mylib.c I include mylib.h:
#include "mylib.h" # notice that I don't have to use "include" in the path
And then I have definitions for the 2 functions that I put in the .h file.
In somefile.c now I am including the library c file, not the .h file (and no need to include git2.h anymore either as that is done in mylib files now).
#include "include/mylib.c"
And this allows me to compile and run the program, just like it did before I separated it into pieces but I know it's possible to include include/mylib.h from the original .c file. I think it requires to build the library before then going into compiling the final program? What steps are required for that?
Right now I'm compiling by hand in a shell script calling GCC in a single shot... so if I need to run more commands to do so, just let me know so that I add them to the script.
In somefile.c, you need to do this:
#include "include/mylib.h"
And make sure you define these functions in mylib.c:
int blah_init(cont char * path, const char * treeish) {
}
int blah_shutdown() {
}
And then declare them in mylib.h:
struct blah {} blah_info;
int blah_init(cont char * path, const char * treeish);
int blah_shutdown();
And when you compile, include both somefile.c and mylib.c as input files.
#include directive is used to insert content of a file somewhere else and it's mostly used to include headers so compiler knows what is what (types, constants, etc), then linker puts all compiled files into one single executable.
to make sure header is included only once to a single file you use something called conditional compilation, it's done with preprocessor (before compilation)
yourlib.h
#ifndef YOUR_LIB_H_ //there are many naming conventions but I prefer this one
#define YOUR_LIB_H_
//all your declarations go here
#endif //YOUR_LIB_H_
//you should put in comment what's that condition for after every endif
now in yourlib.c you include that header and then write your definitions
#include "yourlib.h"
//all your definitions go here
and same thing for your main file, just include the header and compiler knows what to do
#include "yourlib.h"
//your code goes here
Let's say I have two files named "AA.c", "BB.c"
/* in AA.c */
inline void AA(void) __attribute__((always_inline));
void AA()
{
/* do something */
}
and then
/* in BB.c */
#include "AA.c"
extern void funcAA(void);
int main(void)
{
funcAA();
return 0;
}
does funcAA( ) also become inline???
no matter the answer is yes or no, could you explain some more about the under the hood??
including a .c file is equivalent of copying and pasting the file contents directly in the file which includes that, exactly like if the function was directly defined in the including file.
You can see what the compiler is going to compile by trying to compile your file with -E flag (preprocessor output). You'll see your function pasted-in.
So it will be inline just because of the inline keyword, and forced with the always_inline attribute even if the compiler would have refused to inline it because of function size for instance.
Word of advice: know what you're doing when including a .c file from another one. Some build systems/makefiles just scan the directories looking for files called *.c so they can compile them separately. Putting a possibly non-compiling C file there can make the build fail, and if it builds, you could have duplicate symbols when linking. Just don't do this.
If you want to do this, put your function in a .h file and declare it static so it won't fail the link if included in many .c files (each function will be seen as different)
I made up my project, saved main and c source in one file, and saved the header file in the include directory of codeblocks.
When I call my functions from within the project main function, it compiles beautifully.. but when I #include the header to other files for use, the compiler cannot find the functions. The prototypes are in the header, but their definition is in the source code which is in another file. I can access preprocessor constants and macros stored in the header, but the link between the function prototypes and their source code seems not to exist outside the actual project.
My goal was to make header files just like the existing ones I was using (stdio.h, stdlib.h, etc.). I can't find anything helpful on that anywhere. Help me, I've been at this for days!
I know I can make .c files with functions which is way easier, but I want the challenge, want to create lib files, and I'm a performance freak (as far as I know using .h files instead of .c files is much more efficient, can't remember why, though.)
header file:
#ifndef FIRO_H_INCLUDED
#define FIRO_H_INCLUDED
#include <stdbool.h>
#define MA_TA 69
bool checkprime(unsigned long long);
int square(int);
#endif // FIRO_H_INCLUDED
source code:
#include "firo.h"
#include <math.h>
bool checkprime(unsigned long long prime)
{
unsigned long long root=(unsigned long long)(sqrt(prime)+1);
unsigned long long i;
for(i=2; i<=root; i<3?(i++):(i+=2))
{
if(prime%i==0)
return false;
}
return true;
}
int square(int a)
{
return a*a;
}
I was hoping for an answer, not irony. I did read somewhere that segmenting code into .h files and source codes separately would somehow dinamically speed up the process of accesing functions, don't blame me for not knowing how that works. The checkprime function I actualy use, the rest is just for testing.
In codeblocks, you'll have to create a different project for the static lib and build it. Then, you may open your main project's linker settings (Project -> Build Options -> Linker settings tab) and add your library to the "Link libraries" list.
I know this is common in most languages, and maybe in C, as well. Can C handle separating several functions out to a separate file and having them be included?
The functions will rely on other include files, as well. I want the code to retain all functionality, but the code will be reused in several C scripts, and if I change it once I do not wish to have to go through every script and change it there, too.
Most definitely! What you're describing are header files. You can read more about this process here, but I'll outline the basics below.
You'll have your functions separated into a header file called functions.h, which contains the following:
int return_ten();
Then you can have a functions.c file which contains the definition of the function:
int return_ten()
{
return 10;
}
Then in your main.c file you can include the functions.h in the following way:
#include <stdio.h>
#include "functions.h"
int main(int argc, char *argv[])
{
printf("The number you're thinking of is %d\n", return_ten());
return 0;
}
This is assuming that your functions.h file is in the same directory as your main.c file.
Finally, when you want to compile this into your object file you need to link them together. Assuming you're using a command-line compiler, this just means adding the extra definition file onto the end. For the above code to work, you'd type the follow into your cmd: gcc main.c functions.c which would produce an a.out file that you can run.
Declare the functions in header files and then implement them in .c files. Now you can #include the header files into any program that uses the functions and then link the program against the object files generated from the .c files.
Say you have a file with a function that you want to use elsewhere:
int func2(int x){
/*do some stuff */
return 0;
}
what you would do is split this up into a header file and a source file. In the header file you just have the function declaration, this tells the compiler that that function does exist, even if it is in a different file. The header might be called func2.h might look like this:
#ifndef HEADER_FUNC2_H
#define HEADER_FUNC2_H
int func2(int x);
#endif /*HEADER_FUNC2_H*/
The #ifndef HEADER_FUNC2_H part is to make sure that this only gets used once so that there are no multiple definitions going on.
then in the source func2.c file you have the actual function itself:
int func2(int x){
/*do some stuff */
return 0;
}
and in any other file now that you use func2 you have to include the header. You do this with #include "func2.h". So for example if we wanted to call func2 from randomfile.c it would be like this:
#include "func2.h"
/* rest of randomfile.c */
func2(1);
Then the last step is to link the object file that contains the function with the compiler when you compile.
If you want to reuse functions across multple programs, you should place them in a library and link it with the rest of your code.
If you want to share the same definitions (e.g. macros, types, ...) you can place them in a header file and include them with #include.
Please refrain from directly "#include" function code into a source file, it's a bad practice and can lead to very problematic situations (especially if you are a beginner, as your tag suggests).
Consder that normally when you have a set of functions you want to share and reuse, you will need both! You will usually end up with a myfuncs.lib (or libmyfuncs.a) library and a myfuncs.h header.
In the programs where you want to reuse your existing functions, you will include the header and link against the library.
You can also look at how to use dynamic libraries once you have mastered the usage of static libraries.