I am trying to reorganize someone's code and I seem to have hit a wall.
I have a function int fnc() in fnc.c that is called by either main1.c or main2.c. An executable is compiled from either main1.c or main2.c using a makefile:
main1: main1.o fnc.o
gcc main1.o fnc.o -o main1.x
main2: main2.o fnc.o
gcc main2.o fnc.o -o main2.x
main1.o: main1.c
gcc -c main1.c
main2.o: main2.c
gcc -c main2.c
fnc.o:
gcc -c fnc.c
The only problem is, there are two header files header1.h and header2.h to be included in the preamble of fnc.c depending on whether main1.x or main2.x is compiled:
#include "header1.h"
int fnc(){
// do stuff
}
Is it possible to select which header to be loaded depending on whether one types make main1 or make main2?
You can use the -D compiler flag to define a symbol that will be visible to preprocessor. And then to check it with the preprocessor #ifdef directive. Such as:
Makefile:
main1: main1.o fnc1.o
gcc main1.o fnc1.o -o main1.x
main2: main2.o fnc2.o
gcc main2.o fnc2.o -o main2.x
main1.o: main1.c
gcc -c main1.c
main2.o: main2.c
gcc -c main2.c
fnc1.o:
gcc -o fnc1.o -c fnc.c -DCONFIG1
fnc2.o:
gcc -o fnc2.o -c fnc.c -DCONFIG2
And your source:
#ifdef CONFIG1
#include "header1.h"
#elif defined(CONFIG2)
#include "header2.h"
#else
#error "blah"
#endif
int fnc(){
// do stuff
}
Note - this is neither tested nor an optimal solution. Just giving the idea
Related
I have a statically linked library, containing a global variable barvar. I can compile the library with no problems with either gcc-10 or clang (this is on macOS Catalina). Interestingly, the behavior differs between the two when I try to link it into a program that uses the library. Here's the code:
In globvars.h, int barvar is declared:
#ifndef H_GLOBVARS_H
#define H_GLOBVARS_H
extern int barvar;
#endif
In globvars.c, int barvar is defined:
#include "globvars.h"
int barvar;
In foo.c, the function foo sets and prints barvar:
#include <stdio.h>
#include "globvars.h"
void foo()
{
barvar = 10;
printf("barvar is: %d\n", barvar);
return;
}
Here's test.c, the program that uses the library:
void foo();
int main(int argc, char **argv)
{
foo();
return 0;
}
When I compile and link with gcc-10, no problems:
gcc-10 -c foo.c -o foo.o
gcc-10 -c globvars.c -o globvars.o
gcc-10 -c test.c -o test.o
gcc-ar-10 rcs liblinktest.a foo.o globvars.o
gcc -o testlinkrun test2.o -L. -llinktest
When I compile and link with clang, I get an undefined symbol error at the last step:
cc -c foo.c -o foo.o
cc -c globvars.c -o globvars.o
cc -c test.c -o test.o
ar rcs liblinktest.a foo.o globvars.o
cc -o testlinkrun test2.o -L. -llinktest
with error:
Undefined symbols for architecture x86_64:
"_barvar", referenced from:
_foo in liblinktest.a(foo.o)
Any ideas? Interestingly, it appears the only step that has to be done with gcc-10 is compiling globvars.c. I can use clang and the clang linker for all other steps, and everything is fine. Is it possible that clang is optimizing away all the variables in globvars.c? How can I prevent this?
As #EricPostpischil observed in this comment, the issue is that clang defaults to treating barvar as a common symbol. Either changing int barvar; to int barvar = 0;, or compiling with -fno-common, fix the issue.
Beginning with gcc-10, gcc's default behavior is -fno-common instead of -fcommon.
We've got the exercise to create a makefile, which should "create a project bbfoo. bbfoo is linked from barbaz and foo. barbaz is linked from bar and baz. Use the compiler cc (which is gcc on my system) and the linker ld."
I created three simple c files:
bar.c:
int one() {
return 1;
}
baz.c:
int two() {
return 2;
}
foo.c
#include <stdio.h>
int main() {
printf("bar: %d\n", one());
printf("baz: %d\n", two());
return 0;
}
and the following makefile:
bar: bar.c
cc -c -g -o bar.o bar.c
baz: baz.c
cc -c -g -o baz.o baz.c
barbaz: bar baz
ld -shared -o barbaz.o bar.o baz.o
foo: foo.c
cc -c -g -Wno-implicit-function-declaration -o foo.o foo.c
bbfoo: barbaz foo
ld -lc --entry=main -o bbfoo.out barbaz.o foo.o
$ make bbfoo
works without an error and the corresponding files are created. But when I try to run the project with
$ ./bbfoo.out
it displays "File or folder not found".
It works flawless when I use gcc:
$ gcc -o bbfoo.out bar.c baz.c foo.c
$ ./bbfoo.out
bar: 1
baz: 2
What's my mistake? Is it even possible to link a project like this (in two steps)?
Your makefile uses ld to link, but your gcc example uses the compiler driver to link. You should do the same:
bbfoo: barbaz foo
gcc -o bbfoo.out barbaz.o foo.o
The compiler driver may (and in your case clearly does) include a bunch of system-specific stuff that makes your program actually work. Trying to run the linker directly is usually not recommended.
You can use GCC's -v flag if you want to see what the link line it's really using is and copy the flags from that into your makefile if you want, too. But then you're at risk of not picking up important changes in the future.
If you use make you should stick with its basic principle which we can summarize as:
FILE-to-create: files-used-to-create-FILE
shell-commands-that-create-FILE
It is extremely important because make compares last modification times of files to decide what is out of date and what is up to date. It is not a formality and it does change the functionality. So, in your case, you should have:
bar.o: bar.c
cc -c -g -o bar.o bar.c
baz.o: baz.c
cc -c -g -o baz.o baz.c
foo.o: foo.c
cc -c -g -Wno-implicit-function-declaration -o foo.o foo.c
barbaz.so: bar.o baz.o
ld -shared -o barbaz.so bar.o baz.o
bbfoo: barbaz.so foo.o
ld -lc --entry=main -o bbfoo barbaz.so foo.o
Note that make has some nice features that can help factorizing this kind of simple set of rules. Like, for instance automatic variables ($#, $^...), implicit rules (e.g. for building the *.o object files from *.c source files), implicit variables used by the implicit rules (CFLAGS, LD...), target-specific variable values (look at the CFLAGS declaration for foo.o) and many more. Example:
CFLAGS := -g
foo.o: CFLAGS += -Wno-implicit-function-declaration
barbaz.so: bar.o baz.o
$(LD) -shared -o $# $^
bbfoo: barbaz.so foo.o
$(LD) -lc --entry=main -o $# $^
Yes, no rules at all for the object files, make knows already how to build them.
the posted code contains a lot of shortcomings.
Suggest:
bar.h
#ifndef BAR_H
#define BAR_H
int one( void );
#endif
bar.c:
#include "bar.h"
int one() {
return 1;
}
baz.h
#ifndef BAZ_H
#define BAZ_H
int one( void );
#endif
baz.c:
#include "baz.h"
int two() {
return 2;
}
foo.c
#include <stdio.h>
#include "bar.h"
#include "baz.h"
int main( void ) {
printf("bar: %d\n", one());
printf("baz: %d\n", two());
return 0;
}
makefile.mak
.PHONY all
all: bbfoo.out
bar: bar.c bar.h
cc -c -g -o bar.o bar.c -Ibar.h
baz: baz.c baz.h
cc -c -g -o baz.o baz.c -Ibaz.h
libbarbaz.so: baz.o bar.o
ld -shared -o libbarbaz.so bar.o baz.o
foo: foo.c baz.h bar.h
cc -c -g -Wno-implicit-function-declaration -o foo.o foo.c -Ibar.h -Ibaz.h
bbfoo.out: foo.o libbarbaz.so
ld -lc --entry=main -o bbfoo.out foo.o -lbarbaz
Using the short cut variables found in make would greatly shorten this makefile but would make it much more cryptic
I need some help writing a GNU makefile. I have a C program "main.c", which is dependent on the value of "CONSTANT" defined in the file "constants.h".
"main.c"
#include <stdio.h>
#include "constants.h"
void work(void)
{
int array[CONSTANT];
for (int i = 0; i < CONSTANT; i++) {
printf("%d\n", i);
}
}
int main(int argc, char const* argv[])
{
printf("constant=%d\n", CONSTANT);
work();
return 0;
}
"constant.h"
#ifndef CONSTANTS_H
#define CONSTANTS_H
#define CONSTANT 4
#endif
What I'm trying to do here is to compile the program with different values for "CONSTANT". For example, "out1" is compiled with "CONSTANT=1" and with "make all", I should be able to produce all the variants ("out1", "out2" and "out4").
The problem is that "a.o" required by "main.c" also depends on the value of "CONSTANT". So "a.o" must be compiled after "sed%". However, as far as I understand, there is no way in "make" to force orders in dependencies (I guess this is the whole point of using makefiles).
What is the recommended way to address this situation?
"Makefile"
CC= gcc
CFLAGS = -std=c99 -Wall
CONSTANTS = 1 2 4
targets = $(addprefix out, $(CONSTANTS))
seds = $(addprefix sed, $(CONSTANTS))
.PHONY: $(seds)
$(seds): sed%:
sed -i 's/define CONSTANT [0-9]*/define CONSTANT $*/g' constants.h
$(targets): out%: main.c sed% a.o
$(CC) $(CFLAGS) $< a.o -o $#
a.o: a.c constant.h
$(CC) $(CFLAGS) $< a.o -o $#
.PHONY: all
all : $(targets)
Note that I'm aware that I can rewrite "main.c" so that it takes a parameter from the comman line. In practice, many other files other than "main.c" depend on "CONSTANT", so I want to avoid rewriting all these files. I'm also aware that I can do something like "gcc -DCONSTANT=n main.c", but every file dependent on "CONSTANT" must be recompiled as well.
Related Questions
How to specify Makefile target building order without put any physical dependencies?
Force order of dependencies in a Makefile
I'm ... aware that I can do something like "gcc -DCONSTANT=n main.c",
but every file dependent on "CONSTANT" must be recompiled as well.
This needn't be a hindrance if you have your makefile generate
the correct -DCONSTANT=n and distinct object file in every compilation recipe.
Here's an illustration:
constants.h
#ifndef CONSTANTS_H
#define CONSTANTS_H
#ifndef CONSTANT
#define CONSTANT 4
#endif
#endif
foo.c
#include "constants.h"
int foo = CONSTANT;
main.c
#include <stdio.h>
#include "constants.h"
extern int foo;
int main()
{
printf("%d\n",CONSTANT + foo);
return 0;
}
Makefile
CC := gcc
CFLAGS := -std=c99 -Wall
CONSTANTS = 1 2 4
TARGETS = $(addprefix out, $(CONSTANTS))
SRCS := main.c foo.c
define compile =
$(basename $(1))$(2).o: $(1) constants.h
$$(CC) -c -DCONSTANT=$(2) $$(CFLAGS) $$< -o $$#
endef
.PHONY: all clean
all : $(TARGETS)
$(foreach src,$(SRCS),\
$(foreach const,$(CONSTANTS),$(eval $(call compile,$(src),$(const)))))
out%: main%.o foo%.o
$(CC) $^ -o $#
clean:
rm -f $(TARGETS) *.o
This runs like:
$ make
gcc -c -DCONSTANT=1 -std=c99 -Wall main.c -o main1.o
gcc -c -DCONSTANT=1 -std=c99 -Wall foo.c -o foo1.o
gcc main1.o foo1.o -o out1
gcc -c -DCONSTANT=2 -std=c99 -Wall main.c -o main2.o
gcc -c -DCONSTANT=2 -std=c99 -Wall foo.c -o foo2.o
gcc main2.o foo2.o -o out2
gcc -c -DCONSTANT=4 -std=c99 -Wall main.c -o main4.o
gcc -c -DCONSTANT=4 -std=c99 -Wall foo.c -o foo4.o
gcc main4.o foo4.o -o out4
And the resulting programs run like:
$ for i in 1 2 4; do ./out$i; done
2
4
8
There are 4 files:
helper.h //contains the signatures of functions in helper.c
helper.c //implements the signatures in helper.h
file.h //has all the includes needed to run file.h
file.c //this file includes file.h and helper.h
In file.c, I need to use the function that is defined in helper.c in my main function. However, file.c is saying that there is an undefined reference to 'func_found_in_helper.c'
Is this structure correct?
Yes, provided file.c contains
#include "helper.h"
and when building your program you link together helper.o and file.o.
You also need to ensure you compile each of the files with -c so that the compiler only compiles (and not links); do the link later with all the object files.
Here's a working example (I don't actually need a main.h but if you have one of those, #include it from main.c):
main.c
#include <stdio.h>
#include <stdlib.h>
#include "helper.h"
int
main (int argc, char **argv)
{
test ();
exit (0);
}
helper.c
#include <stdio.h>
void
test ()
{
printf ("Hello world\n");
}
helper.h
void test ();
To compile
gcc -Wall -Werror -c -o main.o main.c
gcc -Wall -Werror -c -o helper.o helper.c
To link
gcc -Wall -Werror -o test main.o helper.o
In a Makefile
test: main.o helper.o
gcc -Wall -Werror -o test main.o helper.o
%.o: %.c
gcc -c -Wall -Werror -o $# $<
clean:
rm -f *.o test
To run
$ ./test
Hello world
It's a bit difficult to tell what else might be wrong without the program; my guess is you simply forgot the -c flag to gcc, or forgot to link in helper.o.
undefined reference to 'func_found_in_helper.c'
That's a little odd, as it suggests you have tried to call the function using the '.c' extension, rather than just the function name. Maybe the '.' is just a typo in the question ?
Also a linker will flag an undefined symbol, so it may also be that you have not told the linker where to find helper.o ( the helper.c file compiled to the an object file ). The compiler will start the linker automatically. Did you compile helper.c first ?
According to this question, gcc's -l command requires your library to be named libXXX.a.
Is there a way to link a static library using a different command with gcc? The goal is to avoid this lib- prefix.
Just pass the library as in input file like so:
gcc main.c yourlibrary.a -o prog
Like nunzio said. Just pass it in directly as an input file. He beat me to it, but here's a full example anyway.
mylib.c:
#include <stdio.h>
void say_hi(void)
{
printf("hi\n");
}
main.c:
extern void say_hi(void);
int main(int argc, char**argv)
{
say_hi();
return 0;
}
Makefile:
main: main.c mylib.a
gcc -o main main.c mylib.a
mylib.a: mylib.o
ar rcs mylib.a mylib.o
mylib.o: mylib.c
gcc -c -o $# $^
I realize this assumes some background knowledge in Make. To do the same thing w/o make, run these commands in order:
gcc -c -o mylib.o mylib.c
ar rcs mylib.a mylib.o
gcc -o main main.c mylib.a