Pass variable from C file to makefile - c

In my makefile, I added parameters to linker flags as a variable BOOTLOAD
LDFLAGS += -Wl,--section-start=.bootloader=$(BOOTLOAD)
If i write BOOTLOAD = 0x3800 in makefile everything is working fine.
But i want to pass this variable from C code, so i tried to define it like #define BOOTLOAD 0x3800. But the linker cannot find it.
How should i pass BOOTLOAD from C file?

Instead of "passing" the macro from a C source file (which is possible but not easy), you could instead ask the preprocessor to define the macro when compiling with the -D option:
gcc -DBOOTLOAD=$(BOOTLOAD) -c source_file.c
I recommend you check the GCC preprocessor command line option reference for more information about the -D option.
It is possible to search a specific source file to the macro definition and then set a makefile variable to the extracted value, but it's easier to do it the other way around as shown above.

It seems you have to grep BOOTLOAD from the source code in your makefile as follows:
BOOTLOAD = $(shell grep '#\s*define\s\+BOOTLOAD' YOUR_SOURCE_FILE | awk 'print $3')
LDFLAGS += -Wl,--section-start=.bootloader=$(BOOTLOAD)

Related

Alias or command to compile and link all C files

I recently started compiling/linking my C files by hand using the gcc command. However it requires all of the source files to be typed at the end of the command. When there are many files to compile/link it can be boring.
That's why I had the idea of making a bash alias for the command which would directly type all *.h and *.c files of the folder.
My line in .bashrc is this:
alias compile='ls *.c *.h | gcc -o main'
I found it to work some times but most of the time compile will return this :
gcc: fatal error: no input files
compilation terminated.
I thought that pipe would give the results of ls *.c *.h as arguments to gcc but it doesn't seem to work that way. What am I doing wrong? Is there a better way to achieve the same thing?
Thanks for helping
A pipe does not create command line arguments. A pipe feeds standard input.
You need xargs to convert standard input to command line arguments.
But you don't need (or want) xargs or ls or standard input here at all.
If you just want to compile every .c file into your executable then just use:
gcc -o main *.c
(You don't generally need .h files on gcc command lines.)
As Kay points out in the comments the pedantically correct and safer version of the above command is (and I don't intend this in a pejorative fashion):
gcc -o main ./*.c
See Filenames and Pathnames in Shell: How to do it Correctly for an extensive discussion of the various issues here.
That being said you can use any of a number of tools to save you from needing to do this and from needing to rebuild everything when only some things change.
Tools like make or its many clones, "front-ends" (e.g. the autotools, cmake) or replacements (tup, scons, cons, and about a million other tools).
Have you tried using a makefile? It sounds like that might be more efficient for what you're trying to do.
If you really want to do it with BASH aliases, you have to use xargs to get standard input to command line arguments.
There are several misconceptions here:
the pipe redirects the standard output of the first command to the standard input of the second command; however, gcc doesn't accept the files to compile on stdin, but on the command line;
the wildcard syntax is not something that is magical just to ls, it's the shell that performs their expansion on the command line;
header files are not to be compiled - you compile .c files, which in turn may include headers.
Armed with this knowledge, you'll understand that the correct command something like
gcc -o main *.c
Actually we can do better: first of all, you'll want to change the *.c to ./*.c; this prevents files whose name start with a - from being interpreted as command line options.
Most importantly, you should really enable the compiler warnings, they can be life saver. You'll want to add -Wall and -Wextra.
gcc -Wall -Wextra -o main ./*.c
Finally, it's worth saying that by default you are compiling with optimizations disabled. If you are debugging that's OK, but you want also to add -g to have an executable usable in debugging; otherwise, if the target is speed you should at least add -O2.

Can I use Preprocessor Directives in .ld file

Can I use Preprocessor Directives in .ld file?
I need to to use one of two sets of .ld file and wants to let Build engine deside that using macro, Can I do that?
Yes, you can. You need to run preprocessor manually for your linker script, like this:
in="your_linker_script.ld"
out="generated_script.ld"
cflags=-Iinclude/
gcc -E -P -x c $cflags $in >$out
Flags:
-E specifies GCC to only run preprocessor
-P prevents preprocessor from generating linemarkers (#line directives)
-x c tells GCC to treat your linker script as C source file (it's needed to run GCC with your LD script)
Or you can simply use cpp tool, which is actually C preprocessor.
After this you will be able to use generated linker script to build your program (e.g. in Makefile).
Example
Here is how I solved this problem in my project:
Here is my linker script uses preprocessor (#include directive and CONFIG_TEXT_BASE constant). Excerpt:
#include <config.h>
. = CONFIG_TEXT_BASE;
Here is script to generate preprocessed linker script. Excerpt:
gcc -E -P -x c -Iinclude $cflags $in >>$out
Here is my Makefile, it's generating preprocessed linker script at $(LDS_GEN) target (line 53) and the this generated script is being used to build result binary (line 42). Excerpt:
$(LDS_GEN): $(LDS)
build/gen-lds.sh $(LDS) $(LDS_GEN) $(CFLAGS)
$(APP).bin: $(OBJS) $(LDS_GEN)
$(LD) $(OBJS) -T $(LDS_GEN) -o $(APP).elf
Small update after long time. This way of pre-processing works until the memory file does not contain lines that are fooling the pre-processor. E.g.:
"KEEP(*path/*.o(.rodata .rodata*))"
The "/*" after path is considered comment start (the line contains what is considered a C multi-line comment start and not a match pattern).
This line is valid for the linker but it is considered comment and the output from C pre-processor will remove everything till a supposed closing comment is found:
"KEEP(*path"
The resulting file is clearly invalid for the linker. I have no solution at the moment.
As a simplification of Sam's answer, I added the below to my makefile and away we go :)
PRE_LD_FILE = $(PROG_NAME).ld
LD_FILE = $(PROG_NAME)_generated.ld
$(LD_FILE) : $(PRE_LD_FILE)
cpp $(PRE_LD_FILE) | grep -v '^#' >>$(LD_FILE)

Disable compilation and linking in Code::Blocks?

Programming newbie, I want to disable the compiler/linker and just look at the precompile/ preprocessor's preprocessed code for a program...not sure what this would be called or what the usual method is for doing something like this.
Using the GNU GCC compiler in Code::Blocks, and I looked thru all the various options but not sure the command or what the menu item is called/labeled.
gcc -E source.c -o myfile.i
Here -E is a flag stand's for PRE-Process only.
And -o is another flag which stores the PRE-Processed output of source.c into myfile.i (here .i is common extension given for PRE-Processed files in gcc)
You can use the following option to see the pre-processing files. Normally the compiler will create the files on the fly while trying to create an object file. But at the end removes them.
So in order to view them you can use the command with save-temps.
The output will have the following files:
hello.i-Pre-Processed Output
hello.s-Assembler Output
hello.o-Compiler Output
gcc -save-temps hello.c

Check what files is 'make' including

I'm compiling a kernel module and I'm including <asm/unistd.h>, but I'm not sure if the compiler is using the unistd.h from /usr/includes/ (wrong) or the one from /usr/src/kernel-3.x.x/arch/x86/includes/ (right).
My question is: How can I check which one of those two is the compiler using?
And also, is there a way to force the file from the kernel headers instead of the one from /usr/include?
cpp code.c | grep unistd.h
or
gcc -E code.c | grep unistd.h
To answer the second part of your question:
And also, is there a way to force the file from the kernel headers instead of the one from /usr/include?
You can pass the -nostdinc option to gcc:
"Do not search the standard system directories for header files. Only the directories you have specified with -I options (and the directory of the current file, if appropriate) are searched."
GCC: Options Controlling the Preprocessor

How to replace LD variable in a Makefile to link C objects

I'm writing a Makefile for C. I want be able to specify different programs for compilation and linking via environmental variables. However, I want it works without any additional variables too. I was trying to link with ld. However, the default doesn't link with standard C library.
The question:
How to link C program with ld or $LD
Is it possible to get appropriate flags from cc?
I cannot use $(CC) in place of $(LD). The LD ?= cc doesn't work too.
I want something like this to be true:
Environment variable CC set to tcc.
Environment variable LD unset.
My Makefile compile using tcc and link using system default linker for C.
Unfortunately, some C compilers are unable to link some libraries. I have this problem with tcc and glfw.
P.S.
Linux user
The conditional assignment $(LD) ?= cc can not work, since $(LD) is predefined.
If you want to start make without predefined variables, use the option -R:
> make -p | grep LD
...
LD = ld
...
> make -p -R | grep LD
>
Instead of using ld as the linker, use gcc or g++. They add the appropriate command line options for getting libraries and startup code, etc. In other words:
ld -o main main.o
is equivalent to:
gcc -o main main.o
except that gcc adds all the command line parameters when it calls ld.
In other words: LD=gcc.
One of the main features of tcc is that :
tcc is a compiler and a linker [...] it compile and execute C source directly. No linking or assembly necessary
There's more detail in tcc documentation, it says about linking that :
Dynamic ELF libraries can be output but the C compiler does not generate position independent code (PIC). It means that the dynamic library code generated by TCC cannot be factorized among processes yet.
It means that, if you want to use tcc, you'll need to link with tcc.
As I see, you can define rule-dependent values for variables.
build_with_tcc: CC=tcc compile_tcc
compile_tcc:
## Commands to do a full build with tcc.
build_with_gcc: CC=gcc LD=g++ link_gcc
compile_gcc:
## Commands to compile with gcc.
link_gcc: compile_gcc
## Commands to link with g++.
And build it by calling the appropriate rule.
If you wish, in other hand, to be able to pass an arbitrary compiler toolchain, you will have to have some resctrictions anyway.
The rule:
build_with_arbitrary: compile_arbitrary link_arbitrary
Implies that your build must be done in two steps and the respective rules (compile_arbitrary and link_arbitrary) must obey the same commandline.
So you can invoke make with custom CC and LD variables:
CC=any_cc LD=any_ld make build_with_arbitrary
Lastly, you can add a dirty check for LD being empty in the linker step, and only perform it if not.
link_arbitrary:
[ -n "$(LD)" ] && do_linker_stuff
So you could use build_with_arbitrary even for a compiler that does everything in a single step just by passing:
CC=any_cc LD= make build_with_arbitrary
I hope to have correctly understood your question. Sorry if I misunderstood, and please tell me were I am wrong.

Resources