Can't compile multiple files for Arduino - c

I'm having an issue with compiling code for Arduino if the code is in multiple files. What I have been doing in the past is have a script concatenate the files in another directory and make the project there. I would like to be able to compile directly from my build folder without having to jump through hoops of making sure everything is defined in the right order, etc.
I'm using avrdude to compile from Linux command line, because the Arduino IDE doesn't work very well with my window manager. When I make with multiple files (with appropriate #include statements, I get errors of the following nature, but for all of my methods and variables.
./../lib/motor.ino:3:21: error: redefinition of ‘const long unsigned int MOVE_DELAY’
./../lib/motor.ino:3:21: error: ‘const long unsigned int MOVE_DELAY’ previously defined here
The only other place that MOVE_DELAY is used is inside the void loop() function, and it doesn't redefine it there. The code also compiles fine if concatenate it into one file and run make in that directory, but not if they are in separate files with includes.

I believe your problem is solvable by declaring the objects with the "extern" prefix or external. For example. I often use the SdFat library, in which it is included in both my main sketch and instanced in other libraries.
/**
* \file test.ino
*/
#include <SdFat.h>
#include <foo.h>
SdFat sd;
...
Where I also use the same object in other libraries, such as foo.h.
/**
* \file foo.h
*/
#include <SdFat.h>
extern SdFat sd;
...
If it was not for the prefix of "extern" it would error like yours, as "sd" can not exist twice. Where the extern prefix tells the linker don't make a new instantiation, rather link to the externally instance elsewhere.

Related

Can't resolve C warning in STM32CubeIDE

Facing a a warning which I am not able to get rid of. I am using stm32 MCU and STM32CubeIDE with a standard C11 compiler. Array gpioOutPins is used by in a function call gpio.c file. This function which contains this function call is called from inOut.c file.
Please note that the inOut.c file is in User Application layer while the gpio.c file is in the Kernel (Core) section of the project tree as can be seen below. I was not able to accommodate the whole project tree in the snapshot.
I don't understand why this warning is generated.
Any help is appreciated. Thank you.
An array is deifned in a header file gpio.h:
static uint16_t gpioOutPins[GPIO_OUT_CH_NR] =
{
DOUT_OD_OUT4_Pin,
DOUT_OD_OUT6_Pin,
DOUT_OD_OUT5_Pin,
DOUT_OD_OUT7_Pin,
DOUT_LED_DISABLE_Pin,
DOUT_BUZZ_Pin,
DOUT_OD_OUT8_Pin,
DOUT_OD_OUT3_Pin,
DOUT_OD_OUT2_Pin,
DOUT_OD_OUT1_Pin,
DOUT_ALARM_Pin,
DOUT_12V_PWR_Pin,
DOUT_12V_PWR_Pin
};
The directory structure looks like this:
The warning generated by the compiler is this:
warning: 'gpioOutPins' defined but not used [-Wunused-variable]
Header (.h) files are not a good place to define global variables, because when they are included in source (.c) files, multiple independent copies of them come to existence. They share the same name, but they are actually different variables. And if they are not static, the linker rejects them because of multiple definitions.
Your inOutTask.c probably includes gpio.h header directly or indirectly, so another copy of gpioOutPins comes into existence, which is distinct from the one used in gpio.c. Because you don't use gpioOutPins in inOutTask.c, you get the warning.
The proper way is to move the definition into gpio.c, remove the static keyword, and add extern uint16_t gpioOutPins[GPIO_OUT_CH_NR]; to gpio.h

How do I create a library in C?

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

#include "another_source.c", use inline function( ) there, then does the function( ) become inline as well?

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)

Including .h and .c files to project on the IAR

I am programming stm8s and sht20 from sensirion company with I2C on the IAR. I'm using sht20 sample code: this link
I edited this sample code to my mcu. Then, for example I included i2c_hal.h to my main.c, but functions not working in my main.c file and IAR error is
ERROR LI005 no defition for I2c_Init()
Linking error
For example:
main.c
#include "stm8s.h"
#include "i2c_hal.h"
I2c_Init();
i2c_hal.h
#ifndef I2C_HAL_H
#define I2C_HAL_H
void I2c_Init ();
#endif
i2c_hal.c
#include "I2C_HAL.h"
void I2c_Init ()
{
SDA=LOW;
SCL=LOW;
SDA_CONF=LOW;
SCL_CONF=LOW;
SDA=HIGH;
SCL=HIGH;
}
I copied sht20 files to my project directory. What should I do for this error?
The header file is read by the preprocessor not the linker; if you get as far as linking, it is not a header file issue. The three basic build steps for C code are:
preprocess
compile
link
Your build is failing at the link state. The linker requires all compiled object files and any necessary libraries that constitute your application as input. In your case the most likely issue is that you have not compiled and linked i2c_hal.c (or strictly compiled i2c_hal.c and linked i2c_hal.obj). In the IAR IDE you simply explicitly add i2c_hal.c to your project along with main.c, and all should be good (all other dependencies being satisfied).
I suspect that i2c_hal.c will infact fail compilation since it is missing any declaration of SDA, SCL etc. - you probably need to include stm8s.h there also.
In general the process looks like this (this diagram actually omits pre-processing - i.e. expansion of headers, macros and conditional compilation etc. - but it was the otherwise clearest example I found; the original page does however mention the pre-processor stage, and the preprocessor is normally run automatically when you invoke the compiler in any case):
I have also the same issue with the spi. I got hal_spi_init() linking problem. To resolve the issue you need to enable the I2C in your stm32 hal drivers. In stm32xx_hal_conf.h file we have different #define modules. There you can enable the I2C module or just include the defined symbol in your IAR tool. Then Issue resolved
You need to add the C source files to the project. Header files shall not have any code or data, only the declarations of types , extern variables, macros, static inline functions and function prototypes.

Include c file in another

I want to include a .c file in another. Is it possible right? It works well if I include a header file in a .c file, but doesn't work as well if I include a .c file in another .c file.
I am using Visual Studio and I get the following error:
main.obj : error LNK2005: _sayHello already defined in sayHello.obj
/* main.c */
#include "sayHello.c"
int main()
{
return 0;
}
/* sayHello.c */
#include <stdio.h>
void sayHello()
{
printf("Hello World");
}
I don't know what this error could mean. Time to ask more advanced C coders. :)
I want to include a .c file in another.
No you don't. You really, really don't. Don't take any steps down this path; it only ends in pain and misery. This is bad practice even for trivial programs such as your example, much less for programs of any real complexity. A trivial, one-line change in one file will require you to rebuild both that file and anything that includes it, which is a waste of time. You lose the ability to control access to data and functions; everything in the included .c file is visible to the including file, even functions and file scope variables declared static. If you wind up including a .c file that includes another .c file that includes another .c file und so weiter, you could possibly wind up with a translation unit too large for the compiler to handle.
Separate compilation and linking is an unequivocal Good Thing. The only files you should include in your .c files are header files that describe an interface (type definitions, function prototype declarations, macro defintions, external declarations), not an implementation.
It works, but you need to be careful with how you build the program. Also, as folks have pointed out in comments, it's generally considered a bad idea. It's unexpected, and it creates problems like these. There are few benetfits, especially for what seems like a trivial program. You should probably re-think this approach, altogether.
After doing something like this, you should only compile main.c, and not attempt to link it with the result of compiling sayHello.c, which you seem to be doing.
You might need to tell Visual Studio to exclude the latter file from the build.
Yes, any '.c' file can be included into another program.
As one include '.h' file like 'stdio.h' in the program.
After that we can call those function written into this external file.
test.c::
#include<stdio.h>
#include<conio.h>
void xprint()
{
printf("Hello World!");
}
main.c::
#include "test.c"
void main()
{
xprint();
getch();
}
Output:: Hello World!
This is a linker error. After compiling all your .c files to .obj files (done by the compiler) the linker "merges" them together to make your dll/exe. The linker has found that two objects declare the same function (which is obviously not allowed). In this case you would want the linker to only process main.obj and not sayhello.obj as well (as its code is already included in main.obj).
This is because in main.obj you will ALSO have the sayHello() function due to the include!
sayHello.h
#include <stdio.h>
void sayHello(void);
main.c
#include "sayHello.h"
int main()
{
sayHello();
return 0;
}
You probably defined two times this function
void sayHello()
{
printf("Hello World");
}
one in your current file and one in sayhello.c
You must remove one definition.
The problem seems to be that sayHello.c got compiled into an object file called sayHello.obj, and main.c (also including all the source text from sayHello.c), got compiled into main.obj, and so both .obj files got a copy of all the external symbols (like non-static function definitions) from sayHello.c.
Then all the object files were supposed to get "linked" together to produce the final executable program file, but the linking breaks when any external symbols appear more than once.
If you find yourself in this situation, you need to stop linking sayHello.obj to main.obj (and then you might not want to compile sayHello.c by itself into its own object file at all).
If you manually control every step of the build (like you might when using the CLI of your compiler), this is often just a matter of excluding that object file from the invocation of the linker or compiler.
Since you are using Visual Studio, it's probably making a bunch of assumptions for you, like "every .c file should be compiled into its own object file, and all those object files should be linked together", and you have to find a way to circumvent or disable this assumption for sayHello.c.
One easy and somewhat idiomatic solution might be to rename sayHello.c into sayHello.c.inc.
//THIS IS THE MAIN FILE//
#include "test.c"
int main()
{
multi(10);
}
//THIS IS THE TEST FILE//
#include<stdio.h>
void multi(int a)
{
printf("%d",a*2);
}
POINTS TO BE NOTED:
Here you need to run the program which contains "main()" function.
You can avoid the "stdio.h" header file in main function. Because, you are including the file which already contains the "stdio.h" header file.
You have to call the function from the "main" file.
The including file should be "file_name.c" not "file_name.h". Because usually we use .h extension for the header file. Since we are including another program file and not the header file, we have to use .c. Otherwise it will give you Fatal Error and the Compilation gets terminated.

Resources