I have test.c in which I would like to have the statement
#include "abc.h" (the header file of libabc)
only if test.c has been compiled with libabc as:
gcc test.c -labc
If test.c is simply compiled as
gcc test.c , abc.h should not be included.
How can I do that?
One approach is to use -D to define a macro:
gcc test.c -labc -DABC
#ifdef ABC
#include "abc.h"
#endif
If you're running this command from Bash, then you could in principle create a shell-function wrapper around gcc to automatically add -DABC when -labc is specified:
function gcc ()
{
local arg
for arg in "$#" ; do
if [[ $arg = -labc ]] ; then
command gcc "$#" -DABC
return
fi
done
command gcc "$#"
}
. . . but I don't really recommend that.
Hardly, as the link phase takes place after the compilation is done. You could tweak a Makefile to define a preprocessor macro, and use it as a test condition. I can’t think of any other way.
Related
Using gcc compiler on linux, I have a C program that used command-line argument (one argument) like
./myprog 0
I want to write a makefile that uses conditional compilation so that if I compile like
make SPECIAL=1
then command-line argument is used.
if I compile without SPECIAL like
make
then command-line argument is ignored even if we enter it.
How to make it possible.
I am using following compilation command
gcc -o myprog myprog.c prog2.c prog3.c
The makefile can be trivial but the real work has to happen in the C code. Something like this, as a minimal example:
#include <stdio.h>
int main(int argc, char **argv, char **envp) {
int i;
#ifndef SPECIAL
argc=1;
argv[1] = NULL;
#endif
for(i=1; i<argc; ++i) {
printf(">>%s<<\n", argv[i]);
}
}
Now, you don't even really need a Makefile for this simple program.
bash$ make CFLAGS=-DSPECIAL=1 -f /dev/null myprog
cc -DSPECIAL=1 myprog.c -o myprog
Having said that, making your build nondeterministic by introducing variations which depend on ephemeral build-time whims is a recipe for insanity. Have two separate targets which create two separate binaries, one with the regular behavior, and the other with the foot-gun semantics.
DEPS := myprog.c prog2.c prog3.c # or whatever your dependencies are
myprog: $(DEPS)
myprog-footgun: CLAGS+=-DSPECIAL=1
myprog-footgun: $(DEPS) # same dependencies, different output file
$(CC) $(CFLAGS) -o $# $^
See Target-specific Variable Values in the GNU Make documentation for details of this syntax.
(Notice that Stack Overflow renders tabs in the Markdown source as spaces, so you will not be able to copy/paste this verbatim.)
I would perhaps in fact reverse the meaning of SPECIAL so that it enables the foot-gun version, rather than the other way around (the original version of this answer had this design, just because I had read your question that way originally).
I have several projects in which I use many custom macros. For example,
//prog.c
#include <stdio.h>
#ifdef DBG_LEVEL_1
#define P(d) printf("%s:%d\n", #d, d);
#else
#define P(...)
#endif
#ifdef INLINE
#define INL static inline
#else
#define INL
#endif
INL void func_Sqr(int a)
{
printf("sqr(a):%d\n", a*a);
}
int main()
{
int a = 3;
P(a);
func_Sqr(a);
return 0;
}
I compile this in several ways,
gcc prog.c
gcc -DINLINE prog.c
gcc -DDBG_LEVEL_1 prog.c
gcc -DDBG_LEVEL_1 -DINLINE-DINLINE prog.c
Is there way to set these macros as enabled as default via environment variable?
We can solve this by creating a makefile where these macros are set. But I want to know if there any Linux environment related solution
Is there way to set these macros as enabled as default via environment variable?
Generally, no there is not. Gcc arguments are not affected by environment variables (except maybe DEPENDENCIES_OUTPUT..).
I advise to write a small wrapper function around the command, for example a bash function:
wgcc() {
gcc "${GCCARGS[#]}" "$#"
}
and then doing:
GCCARGS+=(-DA=1 -DB=2)
wgcc something.c
is trivial to do, easy to understand and maintain and communicate with other team members, easy to implement and share. Suprising haisenbugs will be easy to track - wgcc is unique name different then gcc. Still you could overwrite the original command with gcc() { command gcc "${GCCARGS[#]}" "$#"; } or by creating a /usr/local/bin/gcc file, making it a bit more confusing.
But! You can and I woult strongly advise not to do that, because it will be confusing to others and hard to maintain. You can use COMPILER_PATH environment variable to overwrite compiler tools and provide custom options. In steps:
Create a temporary directory
In that directory link all the subprograms of gcc to it's normal prefix, except the tools the behavior you want to modify, like cc1.
Then create cc1 as a script with that will call the original cc1 but will use some environment variable to pass extra arguments.
Then export the path as COMPILER_PATH so gcc will pick it up.
On my archlinux with gcc10.0.1 I did:
mkdir /tmp/temp
cd /tmp/temp
for i in /usr/lib/gcc/x86_64-pc-linux-gnu/10.1.0/{cc1plus,collect2,lto-wrapper,lto1}; do ln -vs "$i"; done
printf "%s\n" '#!/bin/sh' '/usr/lib/gcc/x86_64-pc-linux-gnu/10.1.0/cc1 $GCCARGS "$#"' > cc1
chmod +x cc1
export COMPILER_PATH=/tmp/temp
After that you can:
export GCCARGS=-DA=1
gcc -xc - <<<'int main() { printf("A=%d\n", A); }'
./a.out
> A=1
I'm getting started with multi-thread programming using gcc under Debian 8. I've successfully written and run a multi-threaded test app (foobar.c), but I'm confused by the Makefile (copied from an example). In particular, the command that works is
gcc foobar.c -o foobar -pthread
I'm confused by "-pthread". is that
(a) an option "-p" with value "thread", or
(b) an argument "-pthread" ?
if either case, what is it actually doing? Including some library? Including some object? Setting some other option?
BTW - A similar question 15929739 was asked but never answered. Question 20924412 was not helpful either.
From the man page:
-pthread
Adds support for multithreading with the pthreads library. This option sets flags for both the preprocessor and linker.
To be specific, as of GCC 6.2.1, -pthread will:
#define _REENTRANT 1
Add -lpthread to link against libpthread
How do I know this, you ask?
What preprocessor flags are added?
Let's dump the preprocessor defines and compare them:
$ diff <(gcc -dM -E - < /dev/null) <(gcc -pthread -dM -E - < /dev/null)
> #define _REENTRANT 1
What linker options are added?
Let's dump the ld options passed by GCC and compare them:
diff <(gcc -### -o foo empty.c 2>&1) <(gcc -### -pthread -o foo empty.c 2>&1)
The output here is a bit more verbose, but if we ignore the temporary filename differences, we find:
-lpthread
"-plugin-opt=-pass-through=-lpthread"
Ok, I going to assume this is an easy question. I have a .c file and a Makefile. I'm using Linux 12.10 ubuntu if that matters. I am trying to understand how I write in terminal to get these two files to create an executable, source, and object file in the directory to where these two files are utilizing make. I have nasm installed but not sure if there is something else I need installed. This is currently what I am doing but can't seem to understand the basics behind what I can do in windows but can't seem to get it to work in linux. I have changed the Makefile to except linux.
I know this is probably super easy but I'm pretty new to linux and don't really understand some of the things I think I should be able to figure out pretty easily so I do apologize if this seems to easy.
$ make firstlab.c firstlab
is what I am typing in terminal after I am in the right directory. My
feedback is "
make: Nothing to be done for `homework1.c'.
gcc homework1.c -o homework1
homework1.c: In function ‘main’:
homework1.c:20:5: warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default]
homework1.c:21:5: warning: incompatible implicit declaration of built-in function ‘scanf’ [enabled by default]
"
#include <stdlib.h>
#include <stdio.h>
int main (int argc, char* argv[])
{
int firstNumber = 0;
int secondNumber = 0;
int result = 0;
printf("Enter first value: ");
scanf("%d", &firstNumber);
printf("Enter second value: ");
scanf("%d", &secondNumber);
if(firstNumber >= secondNumber)
result = firstNumber - secondNumber;
else if(secondNumber > firstNumber)
result = secondNumber + firstNumber;
printf("Result: %d\n", result);
system("pause");
return result;
}
Make File:
##########H
PROJECT = Homework1
##################
CC = gcc
# win 32
#RM = del
#linux
RM = rm -f
BIN = $(PROJECT).exe
OBJ = $(PROJECT).o
all: $(BIN)
clean:
${RM} $(OBJ) $(BIN) $(PROJECT).s
$(BIN): $(OBJ)
$(CC) $(OBJ) -o $(PROJECT).exe
$(OBJ): $(PROJECT).s
$(CC) -c $(PROJECT).s -o $(PROJECT).o
$(PROJECT).s: $(PROJECT).c
$(CC) -c $(PROJECT).c -S -masm=intel
Any help is appreciated.
Are you sure you have a makefile? The output you show doesn't seem to line up with that assumption.
make firstlab.c firstlab is a bit weird. You could just replace it with make firstlab and it would have the same results. If you want an object file type, make firstlab.o.
All of that behaviour depends on make's implicit rules. You probably should write a makefile for your project to control the behaviour better. To support creating the assembly file (firstlab.s) you'll have to do that anyway. A rule something like:
%.s : %.c
$(CC) $(CFLAGS) -S -o $# $<
Should do it. You can make similar rules for the executable and the object files. I strongly recommend a quick glance at the GNU Make Manual to get started.
To fix the printf and scanf warnings, add #include <stdio.h> at the top of your program.
I compiled a library which use the g++ instead gcc. First I thought the source code was written in C++ but I found out later that there was not any C++ code in the *.cc files.
To confirm this, I replaced the g++ in the original makefile with gcc. And I still got the correct program.
Anyone can explain this? It was not the first time I met such a situation.
It depends on what exactly you changed in the makefile. gcc / g++ is really just a front-end driver program which invokes the actual compiler and / or linker based on the options you give it.
If you invoke the compiler as gcc:
it will compile as C or C++ based on the file extension (.c, or .cc / .cpp);
it will link as C, i.e. it will not pull in C++ libraries unless you specifically add additional arguments to do so.
If you invoke the compiler as g++:
it will compile as C++ regardless of whether or not the file extension is .c or .cc / .cpp;
it will link as C++, i.e. automatically pull in the standard C++ libraries.
(see the relevant bit of the GCC documentation).
Here's a simple program which detects whether or not it has been compiled as C or C++.
(It makes use of the fact that a character constant has the size of an int in C, or a char in C++. sizeof(char) is 1 by definition; sizeof(int) will generally be larger - unless you're using an obscure platform with >= 16-bit bytes, which you're probably not.)
I've called it test.c and copied it as test.cc as well:
$ cat test.c
#include <stdio.h>
int main(void)
{
printf("I was compiled as %s!\n", sizeof('a') == 1 ? "C++" : "C");
return 0;
}
$ cp test.c test.cc
$
Compiling and linking test.c with gcc, and test.cc with g++, works as expected:
$ gcc -o test test.c
$ ./test
I was compiled as C!
$ g++ -o test test.cc
$ ./test
I was compiled as C++!
$
Compiling and linking test.cc with gcc doesn't work: it compiles the code as C++ because the file ends in .cc, but fails at the link stage:
$ gcc -o test test.cc
/tmp/ccyb1he5.o:(.eh_frame+0x11): undefined reference to `__gxx_personality_v0'
collect2: ld returned 1 exit status
$
which we can prove by separately compiling with gcc, and linking with g++ (to pull in the right libraries):
$ gcc -c test.cc
$ g++ -o test test.o
$ ./test
I was compiled as C++!
$
...gcc has compiled the code as C++ rather than C, because it had a .cc file extension.
Whereas g++ does not compile .c files as plain C:
$ g++ -o test test.c
$ ./test
I was compiled as C++!
$
It could be that the .cc code happens to be C, but was intended to be linked into a C++ library. The internals are different.
g++ automatically links the C++ runtime library — gcc doesn't. Obvoiusly, when it doesn't matter — then it doesn't matter, but, as already pointed out by spraff, it could be intended for future use.
I don't know why they chose to use g++ instead of gcc, but I believe it shouldn't matter, as any valid C program is also valid C++.