**Undefined reference** error while linking two libraries referring to one-another - c

I am getting undefined reference error while trying to compile main that refers to two libraries. I have two files lib1/func1.c and lib2/func2.c in separate folders. Those files contain two functions print1() and print2(), function print1() is calling print2().
I am compiling those separately into two libraries libfunc1.a and libfunc2.a.
But when I am trying to compile main which is calling print1(), I get the following error:
/usr/bin/ld: /home/sv/ztest2/lib1/libfunc1.a(func1.o): in function print1:
/home/sv/ztest2/lib1/func1.c:7: undefined reference to print2
collect2: error: ld returned 1 exit status
make: *** [Makefile:21: DP] Error 1
Here is the code and Makefiles:
Makefile:
TARGET = DP
HOME = /home/slav/FORECAST/ztest2
INCDIRS = -I./ \
-I$(HOME)/lib1 \
-I$(HOME)/lib2
LIBDIRS = -L$(HOME)/lib1 \
-L$(HOME)/lib2
SRCFILES = DP.c
OBJFILES = DP.o
CFLAGS = -g -O3 $(INCDIRS)
all: $(TARGET)
$(TARGET): $(OBJFILES)
cc $(CFLAGS) -o $(TARGET) $(OBJFILES) $(LIBDIRS) -lfunc2 -lfunc1
clean:
-rm *.o $(TARGET)
DP.c:
#include "func1.h"
int main()
{
print1();
return 0;
}
func1.h:
void print1();
func1.c:
#include <stdio.h>
void print1()
{
printf("print1 is called!\n");
print2();
}
func2.h:
extern void print2();
func2.c:
#include <stdio.h>
void print2()
{
printf("print2 is called!\n");
}

Libraries must be listed in the order their symbols are needed.
The command cc $(CFLAGS) -o $(TARGET) $(OBJFILES) $(LIBDIRS) -lfunc2 -lfunc1 tells the linker to first use the func2 library to resolve any pending references in the executable it is building and then to use the func1 library.
Since the linker processes func2 first, and, at the time it does so, there is no pending reference to print2, the linker does not include the module with print2 in the executable.
Later, when the linker is processing func1, it includes the module with print1 in the executable because main uses it. That module print1 uses print2, so including that module adds a new reference to print2. Then, when the linker is done processing func1, it has an unresolved reference. The linker does not go back to func2 to check it again.
Since the func1 library depends on func2, change the link command to cc $(CFLAGS) -o $(TARGET) $(OBJFILES) $(LIBDIRS) -lfunc1 -lfunc2.
(If the func2 library also depends on func1, that is a bad design and should be reconsidered. If it is not changed, asking the linker to reconsider the libraries multiple times, as with -lfunc1 -lfunc2 -lfunc1, might fix the immediate problem, but others can arise.)

Related

Why is my code not throwing a duplicate symbol conflict

Why is my following code not throwing duplicate symbol conflict?
I referred to name mangling, but that seems only when there is difference in parameters. But, here there is not difference in parameters. But, still it does not throw conflict. Why?
good.c
#include <stdio.h>
void printGood() {
printf("I am good");
}
perfect.c
#include <stdio.h>
void printGood() {
printf("I am perfect");
}
A.c
extern void printGood();
void bringGood() {
printGood();
}
B.c
extern void printGood();
void bringPerfect() {
printGood();
}
orchestrator.c
#include <stdio.h>
void bringGood();
void bringPerfect();
int main() {
printf("bringing good");
bringGood();
printf("bringing perfect");
bringPerfect();
return 1;
}
compile line:
gcc -g -c good.c
gcc -g -c perfect.c
gcc -g -c A.c
gcc -g -c B.c
gcc -g -c orchestrator.c
ar rcs libA.a perfect.o A.o
ar rcs libB.a good.o B.o
gcc -o orchestrator orchestrator.o -L. -lA -lB
Why is my following code not throwing duplicate symbol conflict?
The linker looks for undefined symbols in the libraries in the order in which they are specified in the linker line. When it finds a symbol in a library, it uses that definition and stops. It does not check whether that symbol is defined in any of the other libraries specified in the linker line.
In your case, if the linker finds a symbol in A.lib, it stops there. It does not look for the symbol in B.lib.
With your commands, the linker will find function printGood() in object perfect.o in library A. It will not use the function of the same name in good.o from library B. So you effectively link orchestrator.o, A.o, B.o and perfect.o. That's why the executable program prints I am perfect twice and not I am good.
Multiple definition errors are reported only when the object files used in the linker line contain multiple definitions.
You will see the error if you use:
gcc -o orchestrator orchestrator.o a.o b.o perfect.o good.o

call c function from a .c file with a main function

I have two .c files that both have mains. One of the files has a function that I would like to use in the other main. Is it possible to reference this other function without copying and pasting it into the other .c file?
No you don't need to copy and paste, suppose you have this
program-one.c
First program.
#include "common.h" /* This should be implemented */
int main(void)
{
do_program_one_stuff();
common_function();
return 0;
}
program-two.c
Second program.
#include "common.h" /* This should be implemented */
int main(void)
{
do_program_two_stuff();
common_function();
return 0;
}
You need a third .c file and a .h file, like this
common.c
Common Functions Implementation.
void common_function()
{
/* Do it here */
}
common.h
Common Functions Header.
void common_function();
You now can compile a single binary for each program consisting of two files, the program specific .c file and common.c.
The right way to do it is to have a Makefile and generate object code first, and then link the object files togeather, thus compiling each file only once.
Makefile
This is a GNU make Makefile using gcc as the compiler.
CC = gcc
CFLAGS = -Wall -Wextra -Werror -g3 -O0 # enable debug symbols and warnings
LDFLAGS = # linker flags here ...
OBJ = common.o program-one.o program-two.o
all:
$(CC) $(LDFLAGS) common.o program-one.o -o program-one
$(CC) $(LDFLAGS) common.o program-two.o -o program-two
%.o: %.c
$(CC) $(CFLAGS) -c $<
clean:
#rm -fv *.o program-one program-two
EDIT: in response to your comment I would suggest the following
#define main ignore /* Or whatever name you want */
#include "the-student-implementation.c"
#undef main
int main(void)
{
/* This would be your `main()' */
return 0;
}
The best solution is what iharob suggested, but if for some reason that isn't possible, you could surround the main() in the file containing the common function with #ifdef USE_MAIN, then only define the USE_MAIN identifier in the command to build that project. When you build the other project that doesn't have USE_MAIN defined, the preprocessor will cause the second main() to be skipped, so the compiler won't be confused.
But unless this is really needed, I highly recommend splitting this into three files: main1.c, main2.c, and common.c/common.h

Linking files having multiple main function in c

Is it possible to link two C files using makefile which calls each other function but both have a main function of their own.
e.g:
C1.c uses function f() from C2.c.but both have main function and I want the main in C1.c to be considered as main only.
FILES.o=set.o hash.o printnfa.o input.o nfa.o dfa.o terp.o minimize.o defnext.o print_ar.o pairs.o squash.o signon.o print.o lex.o assort.o prnt.o printv.o bintoasc.o ferr.o onferr.o fputstr.o pchar.o driver.o searchenv.o hashadd.o esc.o
PROGRAM= Lexer
INC := -I./debug.h -I./global.h -I./stack.h -I./set.h -I./hash.h
CFLAGS=-DMAIN
all: ${PROGRAM}
${PROGRAM}: ${FILES.o}
${CC} -o $# ${CFLAGS} $(INC) $^ ${LDFLAGS} ${LDLIBS}
Now terp.c has a main and lex.c also has a main. I want only the main for lex.c to be considered.
This will be specific for the linker you use. On Linux you can pass the --allow-multiple-definition flag to the linker in order to use only the first symbol in case of multiple definitions:
${PROGRAM}: ${FILES.o}
${CC} -Xlinker --allow-multiple-definition -o $# ${CFLAGS} $(INC) $^ ${LDFLAGS} ${LDLIBS}
This will omit all errors about duplicate symbols and cause the linker to ignore any redefinitions. Make sure that the object file containing the symbol you wish to use comes before any redefinitions in the list.
The short answer... NO ... it is NOT possible
First of all I would recommend that you refactor the code so that you don't have functions that will be used by many programs in the same file as a main function.
Any way, here is an example on how to use the pre-processor to include only one of the main functions.
We have two source code files both with a main function plus one other function, foo() in file1.c and bar() in file2.c. foo() and baa() are called from both of the main functions.
By changing the MAIN_ALT value in the Makefile we can switch between the main functions:
Use the main function in file1.c:
DEFINES += -DMAIN_ALT=1
Use the main function in file2.c:
DEFINES += -DMAIN_ALT=2
Makefile:
OBJS = file1.o file2.o
DEFINES += -DMAIN_ALT=1
CFLAGS += -Wall $(DEFINES)
prog:$(OBJS)
$(CC) $(CFLAGS) -o $# $^
file1.c:
#include "stdio.h"
#include "def.h"
void foo(){
printf("From foo\n");
}
#if MAIN_ALT == 1
int main(){
printf("Main in file1.c\n");
bar();
foo();
return 0;
}
#endif
file2.c:
#include "stdio.h"
#include "def.h"
void bar(){
printf("From bar\n");
}
#if MAIN_ALT == 2
int main(){
printf("Main in file2.c\n");
bar();
foo();
return 0;
}
#endif
def.h:
#ifndef __DEF_H__
#define __DEF_H__
void foo();
void bar();
#endif

Compiling multiple files in C

I recently asked this question about compiling multiple files in C so that a file main.c can reference a file modules.c. The answer ended up being to make the modules file into a header file and having main import it.
I have now been told that this is an incorrect way to do it, as C supports modular compilation. My Makefile is below, and this is supposedly supposed to be correct, but I receive errors for each function call in main.c -- warning: implicit declaration of function X.
What do I need to do to compile this correctly, with two .c files rather than a .c and .h file? The main.c file has a main() function that needs to be able to call the functions in modules.c.
Makefile:
#################################################################
# Variables
# -- allows C-source and assembly-source files mix. Again, the
# -- indented lines start with a TAB(^I) and not spaces..
#################################################################
CFLAGS = -g -Wall -Werror
LDFLAGS =
CC = gcc
LD = gcc
TARG = driver
OBJS = modules.o main.o
#################################################################
# Rules for make
#################################################################
$(TARG): $(OBJS)
$(LD) $(LDFLAGS) $(OBJS) -o $(TARG)
%.o: %.c %.s
$(CC) $(CFLAGS) -c $<
clean:
rm -f *.o *˜ $(TARG)
print:
pr -l60 Makefile modules.c main.c | lpr
#################################################################
# Dependencies -- none in this program
#################################################################
You've already gotten feedback about using GCC and Makefiles, and it's been noted that the typical way to accomplish your task would be two .c files and one .h file. But it's not required to have a .h file if you use function declarations (which is arguably simpler, just less maintainable and useful), as demonstrated by the following below example.
main.c:
void moduleFunc1(int); // extern keyword required for vars, not for functions
int main()
{
moduleFunc1(100);
return 0;
}
module.c:
#include <stdio.h>
void moduleFunc1(int value)
{
printf("%d\n", value);
}
To compile:
gcc main.c module.c
Edit: After having looked at the assignment you linked, my best guess is actually still that function declarations are what you are looking for. To quote from the assignment, under "Others", #7:
A function should be declared in the module/function where
it is called and not in global scope. Say A calls B and C does
not call it then B should be declared in A only.
In my example, the function declaration is in the module where it's called and seems to meet the A-B-C example. (The confusing part is the global scope comment, but I wouldn't say that the function declaration's scope is global. Observe that if you move the declaration below main(), for example, it messes things up. I haven't found something strictly authoritative for this point, though.)
Having read the assignment, could your instructor possibly mean the following?
main.c:
#include <stdio.h>
int main() {
int plus(int a, int b); /* declaration */
printf("%d ", plus(4, 5));
exit(0);
}
module.c:
int plus(int a, int b) {
return a + b;
}
gcc -Wall -Wextra main.c module.c
The thing is though, that plus() is available in the global namespace. So I am a bit lost.
Just an aside:
3. int next = 234;
printf("%6d ", next);
will print value of next, right justified in 6 columns
6. Use separate statements for declaration and initialization
of a variable as:
int xval;
xval = 100;
Do as I say, not as I do!
You can do this a few ways, but regardless of which you choose, if main.c calls functions from module.c, then main.c must #include a header which declares prototypes for those functions.
The first and simplest way is to just do this:
gcc -Wall -g main.c module.c -o myprogram
The second and more ornate way is to build module.c first as an object file. The primary purpose of this method is to save time when developing/debugging/compiling large programs with multiple parts -- rather than having to recompile the whole thing, you can just recompile the parts the have changed. It also allows you to easily mix and match parts. This is easiest to do with a makefile:
myprogram: main.c module.o
CC $(CFLAGS) main.c module.o -o myprogram
module.o:
CC $(CFLAGS) -c module.c
Notice the "myprogram" target from the makefile works with (prereq) module.o whereas the plain gcc method works with module.c.
If, as per your assignment, you can't use a header or global declarations, you can declare prototypes inside functions:
void somefunc () {
char *whatever (int x); // prototype
printf("%s\n", whatever(12));
}
Is fine, and presuming whatever() is defined somewhere, will work when you compile and run it.

Unable to link to ncurses in shared object

For some reason I have having an issue compiling a shared object that uses ncurses. Even though I include and link with -lncurses, compiling the .so file fails. Please advise.
#include <string.h>
#include "../include/mod_curse.h" /* Includes ncurses.h and friends */
int OnConsoleCmd(McapiS *API, ArgS *CmdArgs) /* Just ignore these, they're included in mod_curse.h */
{
if(!strcmp(CmdArgs->Data, "help"))
{
API->BPrintf(STD, "\n-- mod_curse.so --\n");
return 0;
}
}
int OnLoad(McapiS *API, va_list Args)
{
initscr(); /* These are the problems */
}
/* Time to clean up and unload the module */
int OnDeload(McapiS *API, va_list Args)
{
endwin();
}
Here is the Makefile:
CC = clang
CFLAGS = -Wall -fPIC
# Object Files
OBJ = mod_curse.o
# Header Files
INCLUDE = include/mod_curse.h
# Main Module
mod_setup.so: $(OBJ) $(INCLUDE)
$(CC) -shared -Wl,-soname,mod_curse.so,--no-undefined -o ../../mod_curse.so -lncurses $(OBJ)
# Source Files
mod_curse.o: src/mod_curse.c $(INCLUDE)
$(CC) $(CFLAGS) -c src/mod_curse.c
clean:
rm $(OBJ)
Here are the errors:
3 warnings generated.
clang -shared -Wl,-soname,mod_curse.so,--no-undefined -o ../../mod_curse.so -lncurses mod_curse.o
mod_curse.o: In function `OnLoad':
src/mod_curse.c:(.text+0x81): undefined reference to `initscr'
mod_curse.o: In function `OnDeload':
src/mod_curse.c:(.text+0xb1): undefined reference to `endwin'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [mod_setup.so] Error 1
I needed to change my make command to have -lncurses appear after $(OBJ).

Resources