Pass an argument though makefile linux/unix command line in C - 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.

Related

How to add the compiler command lines in the makefile to the source code

When I execute several different compilation commands via a makefile on one specific sourcecode (c-code). Is there a way to add these compilation commands as a comment to the source code for documentation reason?
You can do it by adding a preprocessor macro defined as a string containing the compiler flags, and then use this macro in an assignment to a constant string pointer.
Something like this in the Makefile
$(CC) $(CFLAGS) -DCFLAGS="$(CFLAGS)" ...
And in one source file do e.g.
const char cflags[] = CFLAGS;
There is no generic way to get it as a part of a comment though.
You could have a special marker in a comment block in a source file, and replace that using e.g. sed in a POSIX enviromnent (like Linux or OSX).
Something like this:
sed -i.bak -e 's#// CFLAGS: .*$#// CFLAGS: $(CFLAGS)#' some_source_file.c
Maybe I misunderstand the question, but this doesn't seem too difficult:
foo.o: foo.cc
#command="$(CXX) $(CPPFLAGS) -c $< -o $#"; echo $$command ;\
sed -i .bak "1{x;s|^|//$$command|;G;}" $< ; \
$$command

Trying to pass preprocessor directive via command line in bash script

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.

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

gcc permanently change c standard

Is there a way of telling gcc to use the c99 standard when compiling c files as a default?
I want to avoid giving it the -std=c99 parameter all the time.
I assume I can do this by creating an alias in the .bashrc file, but seems to be rather inelegant.
You may call c99 instead of gcc (wrapper for gcc, if it's available on your system) or try to modify your gcc spec file. More information here: http://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Spec-Files.html
Here's an unexpected answer. Use a Makefile!
Pros:
Simply type make to build
All options are automatically handled in the build process.
While you're at it, go ahead and enable all warnings, as is good to do. See this.
Easy to scale up to multiple source files
Can handle multi-step builds involving different tools
Cons:
Another tool to learn, another thing to get wrong.
Consider this source:
#include <stdio.h>
int main() {
printf("Hello!\n");
int x = 4;
printf("%d\n", x);
return 0;
}
You could make a Makefile like this:
(Disclaimer, I don't actually know how to write them)
CC=gcc
CFLAGS=-Wall -pedantic -std=c99
LDFLAGS=
SOURCES=$(wildcard *.c)
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=hello
.PHONY: clean
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $#
.cpp.o:
$(CC) $(CFLAGS) $< -o $#
clean:
rm -f *.o $(EXECUTABLE)
And it builds for me.
Likewise, if you remove the -std=c99, it shouldn't be valid C89 code, and indeed, typing make brings up the build error.
Custom compilation suggests you have at a working knowledge of compilers, standards, and basic flags / options. For that reason, I suggest you set shell variables in your .bashrc, .tcshrc, etc., and use them on the command line.
Since the choice of dialect can have an effect on linking: CC="gcc -std=c99", lets you invoke separate compilation commands using $CC -c -O2 ... foo.c, and is also picked up as the default for configure scripts, etc. Of course, you can always override a configure script with CC="gcc -std=c90" or CC="clang". The same applies to a preferred CFLAGS value, e.g.,
CFLAGS="-pipe -W -Wall -O2 -march=core2"
Allows for $CC $CFLAGS -c foo.c commands, and both environment variables are used by default with configure scripts, unless you explicitly override them. I think this is more useful than aliases. But perhaps I've just grown used to my own setup:)
Both of the proposed solutions are, in my opinion, almost what you want, but neither quite gets there.
Makefile solution
As seen here, by defining variables in your Makefile but not defining targets, you can use the make command like a customized pass-through to GCC. So if you create a Makefile in your "sandbox" directory (or wherever you're compiling outside of a real build system) and define the C*FLAGS vars, you'll essentially get what you want. An example Makefile:
CFLAGS=-Wall -std=c99
CXXFLAGS=-Wall -std=c++14
Now, make foo will turn foo.c into an executable called foo.
If you want to do this trick in multiple directories, put your makefile in a known location--say, ~/sandbox--and create the following alias (or something like it) in your .bashrc:
alias usestdmake="ln -s ~/sandbox/Makefile"
Then you can quickly compile a single file anywhere on your machine:
usestdmake
make foo
This has the added advantage of giving the output executable an appropriate name (foo in this case). It has the disadvantage of disabling tab-completion for your compile command (make fo<tab> does nothing, at least on my system).
Pure bashrc solution
The CC/CFLAGS variables mentioned in Brett Hale's answer are fairly standard, so it might be a good idea to define them in your bashrc. You can then use these variables inside of aliases.
In your .bashrc:
CFLAGS="-Wall -std=c99"
CC=gcc
# Use single-ticks to ensure that the variables are evaluated when the alias is evaluated.
alias mycc='$CC $CFLAGS'
On the command line:
cc foo.c # Compile with default CFLAGS
CFLAGS="$CFLAGS -O2" cc foo.c # Compile with modified CFLAGS

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

Resources