I have created two files:
tunables.h
#ifndef TUNABLES_H
#define TUNABLES_H
void tunables_load_conservative();
void tunables_load_aggressive();
extern int timer_x;
#endif /*TUNABLES_H */
and tunables.c
#include "tunables.h"
int timer_x;
void tunables_load_conservative(){
timer_x = 3;
}
void tunables_load_aggressive(){
timer_x = 1;
}
All the other files of my project includes "tunables.h". When I load the project both A.c and B.c calls tunables_load_conservative but if, after a while, I call in file A.c tunables_load_aggressive() in file B.c the timer_x remains 3. Why?
This is my Makefile:
INCLUDE=`pwd`/include
GCCFLAGS= -ansi -O3 -pedantic -Wall -Wunused -I${INCLUDE} -DDEBUG
GCCOTHERFLAGS= -ggdb -pg
all: A B
A: A.o tunables.o
gcc -o A ${GCCFLAGS} ${GCCOTHERFLAGS} tunables.o
B: B.o tunables.o
gcc -o LBfixed ${GCCFLAGS} ${GCCOTHERFLAGS} tunables.o
A.o: A.c
gcc -c ${GCCFLAGS} ${GCCOTHERFLAGS} A.c
B.o: B.c
gcc -c ${GCCFLAGS} ${GCCOTHERFLAGS} B.c
tunables.o: tunables.c
gcc -c ${GCCFLAGS} ${GCCOTHERFLAGS} tunables.c
clean:
rm -rf *.o A B
It looks like you've got two separate processes, A and B. The extern declaration does not set up shared memory across processes, but instead allows different compilation units within the same process to access the same variable.
To share a variable across processes, you will need to use system-dependent IPC methods.
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
I want to link three files but in hierarchical way.
// a.c
int fun1(){...}
int fun2(){...}
// b.c
extern int parameter;
int fun3(){...//using parameter here}
// main.c
int parameter = 1;
int main(){...// use fun1 fun2 fun3}
So, I first compile three files separately into object file a.o, b.o and main.o. And then I want to combine a.o and b.o into another object file tools.o. And eventually use tools.o and main.o to generate executable file.
But, when I try to combine a.o and b.o like ld -o tools.o a.o b.o, the linker says undefined reference to 'parameter'. How could I link those object files into an intermediate object file?
You want the -r option to produce a relocatable object file (think 'reusable'):
ld -o tools.o -r a.o b.o
Working code
abmain.h
extern void fun1(void);
extern void fun2(void);
extern void fun3(void);
extern int parameter;
a.c
#include <stdio.h>
#include "abmain.h"
void fun1(void){printf("%s\n", __func__);}
void fun2(void){printf("%s\n", __func__);}
b.c
#include <stdio.h>
#include "abmain.h"
void fun3(void){printf("%s (%d)\n", __func__, ++parameter);}
main.c
#include <stdio.h>
#include "abmain.h"
int parameter = 1;
int main(void){fun1();fun3();fun2();fun3();return 0;}
Compilation and execution
$ gcc -Wall -Wextra -c a.c
$ gcc -Wall -Wextra -c b.c
$ gcc -Wall -Wextra -c main.c
$ ld -r -o tools.o a.o b.o
$ gcc -o abmain main.o tools.o
$ ./abmain
fun1
fun3 (2)
fun2
fun3 (3)
$
Proved on Mac OS X 10.11.6 with GCC 6.1.0 (and the XCode 7.3.0 loader, etc). However, the -r option has been in the ld command on mainstream Unix since at least the 7th Edition Unix (circa 1978), so it is likely to be available with most Unix-based compilation systems, even if it is one of the more widely unused options.
Trying to compile this code in a.s:
section .bss
global _start
global TestVar
TestVar: RESB 4
section .text
extern main
_start:
and this code in b.c:
extern int TestVar;
void test2(int x, int y)
{
int z = TestVar;
x = z + y;
y = 1;
}
int main(int argc, char **argv) {
return 0;
}
with this makefile:
all: test
test: a.o b.o
ld -melf_i386 a.o b.o -o test
a.o: a.s
nasm -f elf a.s -o a.o
b.o: b.c
gcc -m32 -Wall -g b.c -o b.o
.PHONY: clean
clean:
rm -f *.o test
running the makefile produces:
m#m-All-Series:~/testFolder$ make
nasm -f elf a.s -o a.o
gcc -m32 -Wall -g b.c -o b.o
/tmp/ccjymll2.o: In function `test2':
/home/m/testFolder/b.c:5: undefined reference to `TestVar'
collect2: error: ld returned 1 exit status
makefile:9: recipe for target 'b.o' failed
make: *** [b.o] Error 1
What am I doing wrong?
also, main is there just because if it isn't - the compiler says there is an undefined reference to main in _start in crt1.o, main will never be called, only test2, I don't know if that matters so I included that info as well.
You must use the compiler's -c option if you want to compile a C source into an object file. Without it, gcc tries to go on linking, which is not what you want. E.g.
b.o: b.c
gcc -c -m32 -Wall -g b.c
should get you a bit further.