Trying to pass preprocessor directive via command line in bash script - c

I'm trying to write a bash script that will take in an optional argument,
and based on the value of that argument, compile code using that argument
as a preprocessor directive. This is my file so far:
#!/bin/bash
OPTIMIZE="$1"
if[ $OPTIMIZE = "OPTIMIZE" ] then
echo "Compiling optimized algorithm..."
gcc -c -std=c99 -O2 code.c -D $OPTIMIZE
else
echo "Compiling naive algorithm..."
gcc -c -std=c99 -O2 code.c
fi
However, it doesn't seem to like the "-D" option, complaining that there is a macro name missing after -D. I was under the impression -D defines a new macro (as 1) with name of whatever is specified. I wanted "OPTIMIZE" to be the name of that macro. Any hints?

The -D should be glued to the name (ie -DFOO not -D FOO)
gcc -c -std=c99 -Wall "-D$OPTIMIZE" -O2 code.c
and you forgot to pass -Wall to gcc. It is almost always useful.
BTW, you might consider (even for a single file) using make with two phony targets: the default one (e.g. plain), and an optimized one.

Related

How to run a C program which uses string.h in Ubuntu

My C program uses string.h.. Initially I was not able to compile it. But then I used
$ gcc filename.c -E
Then it complied but I am not able to run it with both
./a.out
./filename
The -E option to gcc invokes only the preprocessor. If you want to compile you need to do this:
gcc -g -Wall -Wextra -o filename filename.c
The -o option specifies the name of the executable to create, the -W options enable the common compiler warnings, and -g includes debugging symbols so you can use tools such as gdb to step through the code line by line.

Details on Makefiles

I am learning about Makefiles and when I first searched the web I did not get any response regarding my question(s).
What are the -o, -f, -c, -g, -Wall, -I, etc. actually called (like +, --, ||, && are called operators), so I can do a correct search on them in the future, and what do they do?
An example I found where this occurs in a Makefile is shown below:
helloworld : helloworld.c
gcc -o helloworld helloworld.c
hellomake: hellomake.c hellofunc.c
gcc -o hellomake hellomake.c hellofunc.c -I.
all: myprog.c
gcc -g -Wall -o myprog myprog.c
(Note: they are parts taken from other Makefiles examples just to show where the "-g", "-Wall", etc. were used
Those flags have nothing to do with make per se. Make is a program that exists to run other programs. Most commonly, but not solely, compilers.
Those flags are flags for your compiler (gcc in this case). So you should be looking at the documentation for your compiler to understand what they do.
Make just runs the commands you give it. You won't find compiler flags in the documentation for make any more than you would in the documentation for your shell, even though you can run the compiler from your shell.
You're conflating two different things. All a makefile does is define a set of commands you can use to shorten a command line call using the program Make. So, in your example, "make helloworld" will call "helloworld.c gcc -o helloworld helloworld.c" on the command line, where "make all" will call "myprog.c gcc -g -Wall -o myprog myprog.c". On the other hand, the program gcc has different command line arguments (such as -o) which tell the program to run a certain way. -Wall, for example, tells it to output all warnings, even trivial ones.
Those are command line flags. The flags you're referring to appear to be flags to gcc (your C compiler).
Much of a Makefile consists of what are essentially shell commands. The "gcc -g -Wall -o myprog myprog.c" is an example of this. You could type the same command in your shell (ie: in a terminal) to do the same thing. What make does is figure out the right time to execute these commands, and it also make it possible to come up with generalized rule (eg: "this is how I always compile .c files into .o files").
"-o", "-f", "-c", "-g", "-Wall", "-I",
Are all options of the Compiler, it's nothing to to with Make. Read the compiler man page.
man gcc

Pass an argument though makefile linux/unix command line in C

my makefile is:
CFLAGS=-g
all: mcast_client mcast_server
mcast_client: mcast_client.o $(ARG1)
mcast_server: mcast_server.o
clean:
rm -f mcast_client mcast_server mcast_client.o mcast_server.o
in the command window i type,
$ make ARG1=hello, world!
is this correct?
Use:
$ make ARG1="hello, world!"
Your invocation make ARG1="hello, world!" is almost correct (but the quotes are needed for the shell), but your Makefile is not.
A more realistic approach would be to pass the message as a preprocessor macro.
Assume hello.c contains (in the middle of some C function)
printf("%s\n", MESSAGE);
Then you could have a Makefile rule like
hello.o: hello.c
$(COMPILE.c) -DMESSAGE=\"$(MSG)\" $< -o $#
The quotes are backslashed because the preprocessor macro MESSAGE should have quotes.
And finally you could invoke
make "MSG=hello friend"
Beware that this won't work if MSG contains quotes " or backslashes \ .... In the command above the quotes are interpreted by the shell...
Notice that you are supposed to invoke make with the same command every time... (since hello.o won't be rebuilt if the MSG has changed).
BTW, take the habit of always compiling with -Wall so
CFLAGS= -Wall -g
and look at predefined rules of make given by make -p
Consider using remake (notably invoked with -x) to debug tricky or complex Makefile-s.

GCC and makefile: Only show errors and warnings

I have a makefile that compiles every .c file in my project. For each file, I get the whole compile command printed out to the shell, with all the options and flags. This is the example output for one file:
arm-none-eabi-gcc -c -mcpu=cortex-m3 -O0 -dM -g -gdwarf-2 -mthumb
-fomit-frame-pointer -fverbose-asm -Wa,-ahlms=src/sim/sim_configuration.lst -include ./lib/stm32core/stm32f2xx_conf.h -I . -I./lib/ARMStandardLibrary
-I./lib/LwIP -I./lib/LwIP/src/include -I./lib/LwIP/src/include -I./lib/LwIP/src/include/ipv4 -I./lib/LwIP/src/include/ipv6 -I./lib/FatFS -I./lib/stm32core -I./src -I./src/sim -I./src/sd -I./src/tftp src/sim/sim_configuration.c -o src/sim/sim_configuration.o
The problem is that various warnings get lost inside this whole mess of command outputs. Is there a way to only print the warnings and errors that appear (not the original command)?
Execute make with the -s option. From the man page.
-s, --silent, --quiet
Silent operation; do not print the commands as they are executed.
Just prepend the command with the # symbol.
If you rely on built-in implicit rules, you will have to make them explicit or, in your specific case, you could use:
.SILENT: *.o
for silencing all commands used for building to the %.o targets.
You could always filter all the output from stdout, which should leave you with all the errors on stderr:
make 1>/dev/null
Use # before a command to hide the it:
rule1:
#gcc someting

compile with -ansi -pedantic -Wall switches automatically with gcc

We are required to compile C source codes using gcc in this manner:
gcc -ansi -pedantic -Wall program.c
I'm wondering how can I 'automate' this so when I enter:
gcc program.c
It will automatically compile with the 3 switches. Is this possible?
You can also use the implicit rules of make, so that you don't have to write a makefile for every program. Make will automatically call the compiler if you say make foo and there exists a foo.c file in the current directory. To add flags to this define the variable CFLAGS in your environment, e.g. in bash add export CFLAGS="-Wall -pedantic -ansi" to .bashrc.
If your program depends on multiple files however you'll have to create a makefile, but for C compilation you can get away with just listing dependancies so long as one of them has the same base name as a target.
For example for this makefile:
# Makefile
foo:foo.o bar.o
running make will execute the commands
gcc $CFLAGS -c -o foo.o foo.c
gcc $CFLAGS -c -o bar.o bar.c
gcc -o foo foo.o bar.o
without you having to add any rules.
To automate the build of any number of build steps / complex parameters, you should use a makefile.
Once you have a makefile you simply need to type: make
alias gcc="gcc -ansi -pedantic -Wall"
But as #Brian said, you really should use a makefile, or better, a build system like CMake or SCons.
A makefile would be the traditional way, especially as part of a larger build process.
If you frequently want to build without a makefile, you could define an alias in your .bashrc or equivalent: alias gcc=gcc -ansi -pedantic -Wall.
You can use a shell script that takes some cues by how its called and invokes make after setting CFLAGS appropriately for the occasional one-off build.
Lets say you have /usr/bin/compile , which is a shell script that looks at $0 to see what name actually invoked it. You then make symbolic links to it named pedantic, fullwarn, etc.
In the shell script itself, something like:
OLDCFLAGS=$CFLAGS
WHATAMI=$(basename $0)
case "$WHATAMI" in
pedantic)
export CFLAGS="-Wall -pedantic -ansi"
make $#
exit $?
;;
c99)
export CFLAGS="-std=c99 ... ... ..."
....
Then, to compile foo.c with the extra naggy flags:
pedantic foo
This is handy, as I said for one-off builds, e.g trying to compile code that someone posted in a question, or working out how to use a new library, etc.
For anything else, just use a makefile, as others have said.

Resources