Undeclared Identifiers in header file with AVR-GCC - c

I created the following header file with definitions for AVR pins to be used in my code.
#define LED_PORT PORTB
#define LED_PIN PINB
#define LED_DDR DDRB
#define LED0 PB0
I encounter two failures I am not able to solve.
1) I have two issues in this header file, shown here:
2) Also the functions I created in the header file for USART in the USART.h file, I implemented, are not being recognized
I actually do not understand why that is. As the code clearly has the header file implemented.
#ifndef F_CPU
#define F_CPU 1000000UL
#endif
#include <avr/io.h>
#include <util/delay.h>
#include "pinDefinition.h"
#include "USART.h"
int main(void) {
char serialCharacter;
LED_DDR = 0xff;
initUSART();
printString("Hello World!\r\n");
while (1) {
serialCharacter = receiveByte();
transmitByte(serialCharacter);
LED_PORT = serialCharacter;
}
return (0);
}
The compiler I am using is AVR-GCC.
Furthermore, when I include the USART.c directly, then everything is working fine. I don't understand why the header file is not working though.
I created a script that runs the compiler/linker:
#!/bin/bash
avr-gcc -g -Os -mmcu=atmega328p -c code.c util.c USART.c
avr-gcc -g -mmcu=atmega328p -o code.elf code.o
avr-objcopy -j .text -j .data -O ihex code.elf code.hex
avr-size --format=avr --mcu=atmega328p code.elf
This returns the above mentioned error.
The USART.h looks like this:
/* These are defined for convenience */
#define USART_HAS_DATA bit_is_set(UCSR0A, RXC0)
#define USART_READY bit_is_set(UCSR0A, UDRE0)
#include <stdint.h>
void initUSART(void);
void transmitByte(uint8_t data);
uint8_t receiveByte(void);
void printString(const char myString[]);
void readString(char myString[], uint8_t maxLength);
void printByte(uint8_t byte);
void printWord(uint16_t word);
void printBinaryByte(uint8_t byte);
char nibbleToHex(uint8_t nibble);
char nibbleToHexCharacter(uint8_t nibble);
void printHexByte(uint8_t byte);
uint8_t getNumber(void);
I really require some help as I am trying to solve this now for three days and read a lot of different sources (I am getting my ropes together still with C so please be mindful).C

I created a script that runs the compiler/linker:
avr-gcc -g -Os -mmcu=atmega328p -c code.c util.c USART.c
This command generates three files: code.o, util.o and USART.o, whereas the following link command only links one object file:
avr-gcc -g -mmcu=atmega328p -o code.elf code.o
Hence, all functions from the latter two compilation units are missing, which leads tu bunch of "undefined reference to" from the linker. Fix is to link all three object files:
avr-gcc -g -mmcu=atmega328p -o code.elf code.o util.o USART.o
Undeclared Identifiers in header file
A header file (module.h) in C just contains declarations of functions in the module (module.c), but the implementation / definition of the functions is in the *.c file.
(One exception are static inline functions which are defined in the header, but this is not the case for the undefined references from your code.)

Related

Compiling header files in ubuntu. What do I type in terminal?

I'm pretty sure this is a simple question but I've searched online for about half an hour.
I have 3 files:
02_01.c
#include <stdio.h> // Notice the library included in the header of this file
#include <stdlib.h>
#include "myLibrary.h" // Notice that myLibrary.h uses different include syntax
#define MAX_LENGTH 21.8
#define WORK_WEEK 5
int main(void) {
function1();
return EXIT_SUCCESS;
}
myLibrary.c
void function1(void){
puts("It works :)");
}
void function2(void){
//This function does nothing as well
}
myLibrary.h
#ifndef MYLIBRARY_H_
#define MYLIBRARY_H_
void function1(void);
void function2(void);
#endif /* MYLIBRARY_H_ */
First, I navigate to my working directory.
Normally in a file with no local headers I would type:
gcc -o 02_01 02_01.c
./02_01
and it would work.
I've tried a variety of things like:
gcc -o 02_01 02_01.c myLibrary.c
which gives me an error "implicit declaration of function 'puts'
gcc -o myLibrary myLibrary.c which also gives the same error.
What should I be typing in the terminal in ubuntu?
So I'm assuming that the puts() function in myLibrary.c is not connected to 02_01.c which is where I include stdio.h.
You must include required headers in every file, where you using included functions. In your case, you must include #include <stdio.h> in beginning of your myLibrary.c file.
Also, you probably want to build .a library and link with it later.
So, finally:
Compile lib:
gcc -c -o mylib myLibrary.c
Make static lib:
ar rcs libMyLib.a mylib
Compile app and link together:
gcc -o 02_01 02_01.c -L. -lMyLib

C - Makefile compiles after header file changes, but changes dont take effect

I have 3 files in this program, lab4.c, functions.h, functions.c
The lab4.c calls a function multiply(), whose prototype is in functions.h and is defined in functions.c. Multiply then used multiple other functions from functions.c. The only includes I have for this is in lab4.c including functions.h, do I need more? The problem I am having is described below
lab4:
#include <stdio.h>
#include <stdlib.h>
#include "functions.h"
int main(void) {
...
}
functions.h:
#ifndef FUNCTIONS
#define FUNCTIONS
void divideByPowerOf2(unsigned int* a, int power);
void multiplyByPowerOf2(unsigned int* a, int power);
...
#endif /* FUNCTIONS */
functions.c:
void divideByPowerOf2(unsigned int* a, int power){
*a >>= power;
}
void multiplyByPowerOf2(unsigned int* a, int power){
*a <<= power;
}
...
Currently, my makefile looks like this:
Makefile:
#Makefile
all: lab4
lab4: lab4.o functions.o functions.h
gcc -Wall -o lab4 lab4.o functions.o
lab4.0: lab4.c
gcc -c lab4.c
functions.o: functions.c
gcc -c functions.c
now this will recompile when I change the header file, but the changes dont actually take effect. For example, if I change the header file to
#ifndef FUNCTIONS
#define FUNCTIONS
void divideByPowerOf2(unsigned int* a, int power);
//void multiplyByPowerOf2(unsigned int* a, int power);
...
#endif /* FUNCTIONS */
the program still works just fine. Im assuming I may have messed up linking the files with includes and everything, as that usually confuses me. For example, does functions.c need to refer to anything? and does functions.h need any kind of reference to the .c files? How do I get this to work properly so that if I change the header file, it recompiles and actually uses the new header
Thanks for any help!
First, there's a typo here:
lab4.0: lab4.c
should be
lab4.o: lab4.c
then, your function.h should be on the source => object dependency lines, not on the object => executable line, else, if you change the .h file, it just re-links without rebuilding the .o files: it changes nothing.
Moreover, it's good to use -Wall, but you have to use it when you compile your files, not when you link the executable, or you'll miss the actual compilation warnings (-Wall during the link phase only is pretty useless).
For instance, the -Wall flag would show you that commenting a prototype generates an "implicit declaration" warning (which can lead to an improper call/return values of a function). It's even more effective with -Werror, which turns warnings into errors, so you cannot ignore warnings.
Here's how your makefile should look like:
all: lab4
CFLAGS = -Wall
lab4: lab4.o functions.o
gcc -o lab4 lab4.o functions.o
lab4.o: lab4.c functions.h
gcc $(CFLAGS) -c lab4.c
functions.o: functions.c functions.h
gcc $(CFLAGS) -c functions.c
note that if you only have 2 source files and they're small enough, you could even not use the make file by just running:
gcc -Wall -o lab4 lab4.c functions.c
in a script. That's not adapted if you have too many / big source files, because it rebuilds everything everytime.

How to deal with function definitions in header files?

Is there any way I can compile a poorly designed header file to a object file without changing file extension or content using gcc, or do I have to copy the file/edit it? (This because I am using a public SDK, i.e. I do not have permission to edit the header file, and because using cp in my Makefile seems like a major hack, and time consuming too)
Example
main.c
#include <print.h>
#include <app.h>
int main(void) {
print("Starting app . . . ");
run();
}
app.h
#ifndef APP_H
#define APP_H
int runApp(void);
#endif
app.c
#include <print.h>
#include <app.h>
int runApp(void) {
print("This is my app!");
return 0
}
print.h
#ifndef PRINT_H
#define PRINT_H
int print(char* str) {
printf(str);
return 0;
}
#endif
Which is compiled using:
$ gcc -o main.o main.c
$ gcc -o app.o app.c
$ gcc -o main main.o app.o
The SDK example programs use a single object file (gcc -o main.o main.c & gcc -o main main.o), but that would just get really messy in my case.
Create
_print.h
int print(char* str);
print.cpp
#include <print.h>
and change your includes to "_print.h"

gcc compile multiple files

I have these five source
main.c src_print1.c src_print2.c header_print1.h header_print2.h
the contents are simple and are as following for respective files:
main.c
#include "header_print1.h"
#include "header_print2.h"
int main(int argc, char** argv) {
print1();
print2();
return 0;
}
header_print1.h
#ifndef PRINT_1
#define PRINT_1
#include <stdio.h>
#include <stdlib.h>
void print1();
#endif
header_print2.h
#ifndef PRINT_2
#define PRINT_2
#include <stdio.h>
#include <stdlib.h>
void print2();
#endif
src_print1.c
#include "header_print1.h"
void print1() {
printf("Hello 1\n");
}
src_print2.c
#include "header_print2.h"
void print2() {
printf("Hello 2\n");
}
Using gcc I have tried to compile using the following command line:
gcc -I ./ -o test -c main.c src_print1.c src_print2.c
Everything is in the same folder.
The error I get is:
gcc: cannot specify -o with -c or -S with multiple files
I looked up at gcc manual, but actually I don't understand what to do in this case, since usually I use IDE and not the command line.
IMHO, if you rewrite your compilation statement like
gcc -I./ -o test main.c src_print1.c src_print2.c
You'll be good to go. There is no need for -c flag [NOTE] when you're specifying the output binary using -o.
Also, as mentioned here, all the files are in same directory, you can even shorten the statement as
gcc -o test main.c src_print1.c src_print2.c
Suggestion: While the above change(s) will do the job, this is not considered an elegant way of doing so. Please consider creating a makefile which will make your life easier.
[Note]:
Regarding the -c option, as per the online gcc manual, (emphasis mine)
-c
Compile or assemble the source files, but do not link. The linking stage simply is not done. The ultimate output is in the form of an object file for each source file.
So, it should be clear by now, why you got the error.

multiple definition in g++?

The code is as follows:
global.h
#ifndef GLOBAL_H
#define GLOBAL_H
#include <stdio.h>
int test;
void test_fun(void);
#endif
global.c
#include "global.h"
void test_fun()
{
printf("%d\n", test);
}
main.c
#include "global.h"
int main(void)
{
test_fun();
test = 1;
printf("%d\n", test);
}
Makefile using gcc compiler
main: main.o global.o
gcc -o main main.o global.o
main.o: main.c global.h
gcc -c main.c
global.o: global.c global.h
gcc -c global.c
clean:
rm -f global.o main.o main
This works well.
However, when I change my code to C++, as follows:
global.h
#ifndef GLOBAL_H
#define GLOBAL_H
#include <iostream>
int test;
void test_fun(void);
#endif
global.cpp
#include "global.h"
void test_fun()
{
cout << test
}
main.cpp
#include "global.h"
int main(void)
{
test_fun();
test = 1;
std::cout << test;
}
Makefile using g++ compiler
main: main.o global.o
g++ -o main main.o global.o
main.o: main.cpp global.h
g++ main.cpp
global.o: global.cpp global.h
g++ global.cpp
clean:
rm -f global.o main.o main
The code above throws the output:
global.o:(.bss+0x0): multiple definition of `test'
What makes the different here?
You've int test; in a header which is included in 2 TUs, hence the error. Both the translation units main.c (or .cpp depending upon the compiler used) and global.c have global.h included, which leads to two definitions of the same variable in two object files, thus the linker error.
Pass test as an arguement to test_fun, thereby avoiding the usage of a global.
If you absolutely have to share the variable between the TUs, then remove int test; from global.h and in main.cpp do
int test;
and in global.cpp do
extern int test;
As an aside, since it's a global variable, test would be initialized to 0 and hence in main when you test_fun();, it should print 0 and then after setting it to 1, it'll print 1.
It's illegal in both C and C++ from a language standpoint, but as for why it works with a C compilers (like GCC) is because they implement a common extension, a legacy cruft.
... You are using a different programming language

Resources