Produce both assembly and object file with gcc/clang: Possible? How? - gcc

Is it possible to produce both the object file and the source file in once command with gcc/g++/clang/clang++ ? How?
I need to pass a lot of other options, so I would like to avoid duplicating them in 2 separate commands:
gcc -S test.cc # produce assembly
gcc -c test.cc # produce object file

You can give the -save-temps option to gcc: it will leave all the temporary files (including the .s files) in the current directory (works also with clang):
gcc -c --save-temps test.cc
or use the -Wa,-aln=test.s option:
gcc -c -Wa,-aln=test.s test.c
From gcc documentation:
-Wa,option
Pass option as an option to the assembler. If option contains commas, it is split into multiple options at the commas.
From as documentation:
-a[cdghlmns] Turn on listings, in any of a variety of ways:
-al include assembly
-an omit forms processing
[...]
You may combine these options; for example, use -aln for assembly listing without forms processing.
Clang has an integrated assembler that should be switched off (How to switch off LLVM's integrated assembler?):
clang++ -c -no-integrated-as -Wa,-aln=test.s test.c

Related

How to create makefile for Linux for the next command - gcc -shared -home/ time.c /libperi.a -o time.so

How to create a makefile for Linux for the next command?
gcc -shared -home/ time.c /libperi.a -o time.so
First, pick a name. This command appears to build time.so, so that's a good name.
The makefile is just a text file. Write it like this:
time.so:
gcc -shared -home/ time.c /libperi.a -o time.so
That whitespace before the gcc is a TAB, not spaces.
Once you have that working, you can read the manual and learn more about Make, which will allow you to write more powerful rules.

Can you pass your code directly into gcc? For example: gcc -? 'int main(){return 0;}'

Can you pass your code directly into gcc? If so what is the command line option for it?
For example:
g++ -? 'int main(){return 0;}'
I need to know because I am using a system command and I rather not make files:
system("g++ -C "+code_string+" -o run.out");
Basile Starynkevitch solution worked, however I am getting compile errors when I use newlines:
echo '#include\nint main(){printf("Hello World"); return 0;}' | g++ -x c++ -Wall -o myprog /dev/stdin
Edit: fixed it
echo -e '#include\nint main(){printf("Hello World"); return 0;}' | g++ -x c++ -Wall -o myprog /dev/stdin
You could ask GCC to read from stdin. Read the Invoking GCC chapter of its documentation. Use its -x option with /dev/stdinor with -:
echo 'int main(){return 0;}' | g++ -x c++ -O -Wall -o myprog /dev/stdin
BTW, since int main(){return 0;} is a valid C program, you could use
echo 'int main(){return 0;}' | gcc -x c -O -Wall -o myprog -
Programatically, you should consider using popen(3) to get a some FILE* handle for a pipe(7) (so FILE* f = popen("g++ -x c++ -O -Wall -o myprog /dev/stdin", "w"); then check that f is not null) and fprintf into it then pclose it at last. Don't forget to test the status of pclose.
However, most of the time spent by GCC is not parsing (use -ftime-report developer option to find out). You often want to ask it to optimize (with -O2 -march=native or just -O for example), and you surely want to ask for all warnings (with at least -Wall and perhaps also -Wextra).
If you want to produce some plugin code in /tmp/someplugin.so from some emitted C++ code in /tmp/myemitted.cc to be dynamically loaded on Linux, compile it as position-independent code into a shared object dynamic library with e.g.
g++ -o /tmp/someplugin.so -fPIC -shared -Wall -O /tmp/myemitted.cc
etc.... then use dlopen(3) on /tmp/someplugin.so with dlsym(3) to fetch some loaded symbols. My GCC MELT is doing this.
Since parsing time is negligible, you could instead write C or C++ code in some temporary file (inside /tmp/ or /run which is often some fast tmpfs on most Linux systems, so writing into it does not require disk I/O).
At last, recent GCC (use at least GCC 6) also has GCCJIT (actually libgccjit). You could use it to build some representation of generated code then ask GCC to compile it.
See also this and that. Read the C++ dlopen mini howto and the Program Library HowTo, and Drepper's How To Write Shared Libraries
I rather not make files
Generating a temporary file (see mkstemp(3) etc... and you practically could also general some random file name under /tmp/ ending with .c, then register its removal with atexit(3) passed some function doing unlink(2)...) is really quick (but you should build some kind of AST in memory before emitting C++ or C code from it). And using some Makefile to compile the generated code with some make command has the advantage (for the advanced user) to be able to change compilers or options (by editing that Makefile to configure make).
So you are IMHO wrong in avoiding temporary files (notice that gcc & g++ are also generating and deleting temporary files, e.g. containing some assembler code). I would suggest on the contrary generating a temporary file (matching /tmp/mytemp*.cc) using some random numbers (see random(3); don't forget to seed the PRNG with e.g. srandom(time(NULL)); early in your main). It could be as simple as
char tmpbuf[80];
bool unique;
do { // in practice, this loop is extremely likely to run once
snprintf(tmpbuf, sizeof(tmpbuf), "/tmp/mytemp_%lx_p%d.cc",
random(), (int)getpid());
unique = access(tmpbuf, F_OK);
} while (unique);
// here tmpbuf contains a unique temporary file name
You coded:
system("g++ -C "+code_string+" -o run.out");
Beware, + is usually not string catenation. You might use snprintf(3) or asprintf(3) to build strings. Or use in C++ std::string. And if you use system(3) you should check its return code:
char cmdbuf[128];
snprintf(cmdbuf, sizeof(cmdbuf), "g++ -Wall -O %s -o run.out", tmpbuf);
fflush(NULL);
if (system(cmdbuf) != 0) {
fprintf(stderr, "compilation %s failed\n", cmdbuf);
exit(EXIT_FAILURE);
}
BTW, your example is wrong (missing <stdio.h>); it is C code, not C++ code. It should be
echo -e '#include <stdio.h>\nint main(){printf("Hello World"); return 0;}' \
| gcc -x c -Wall -O -o myprog -
PS. My answer is focused on Linux, but you could adapt it for your OS.

How do you pass the --start-group and --end-group flags to gcc when using scons?

In scons, how do you implement the --start-group and --end-group gcc flags? These should wrap a particular set of LIBS, but I couldn't find a PREFIX/SUFFIX option that wraps the entire (or partial set of) input to LIBS.
In case you're wondering what gcc flags I'm talking about, read more here:
GCC: what are the --start-group and --end-group command line options?
You're right that there is no built in prefix/suffix for this wrapper. The command line options specifying the list of libraries passed to the link command is computed based on the LIBS environment variable and stored in the _LIBFLAGS environment variable. _LIBFLAGS is then used as a part of the complete linker command line.
The defaults, defined in Tool/link.py in the SCons library, look something like:
env['LINKCOM'] = '$LINK -o $TARGET $LINKFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
env['_LIBFLAGS']='${_stripixes(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, LIBPREFIXES, LIBSUFFIXES, __env__)}'
Assuming that you want to wrap the entire set of libraries, then in your environment, you can edit either the LINKCOM or the _LIBFLAGS variables to add the options:
# SConstruct
env = Environment(
CC = 'gcc',
LINKCOM = '$LINK -o $TARGET $LINKFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS -Wl,--start-group $_LIBFLAGS -Wl,--end-group'
)
#env.Prepend(_LIBFLAGS="-Wl,--start-group ") # the trailing space is required
#env.Append(_LIBFLAGS=" -Wl,--end-group") # the leading space is required
env.Program('foo', ['foo.c'], LIBS='m')
I think editing LINKCOM is a little less invasive. In my trivial example, this generates:
$ scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
gcc -o foo.o -c foo.c
gcc -o foo foo.o -Wl,--start-group -lm -Wl,--end-group
scons: done building targets.
If you want to group just a subset of libraries, then you'll have to use separate LIBS variables for the "wrapped" and "unwrapped" libraries and duplicate the _LIBFLAGS function in a separate variable appended to LINKCOM.

What does -L ${SOME_LIB} means in a Makefile?

Here I am compiling a C code with the following Makefile.
MAIN:
g++ -c -o td.o -I/home/user/dp/pro/include td.c
g++ -c -o disk.o -I/home/user/dp/pro/include disk.c
g++ -o disk disk.o tds2.o -L ${DP_LIB} -L ${LIPN_LIB} -lgnb -lgtd -lnbl -lpin
./disk.exe RUN.dat
What is the purpose of -L ${DP_LIB} here? Precisely, I wish to know the function of ${}.
If it is linking a library, how is it different from -llib?
This makefile is by far very crude (I have seen bigger and better ones). I am new to makefiles, but atleast this one works.
The -L options is telling the linker to add a path to the list it uses to search for libraries. The ${DP_LIB} thing is how variables are used in makefiles. Presumably DP_LIB is a path to somewhere.
All this should be very clear if you just read the documentation and the actual makefile.
With -Ldir you specify a directory where the linker searches for libs. The lib files themselves are specified with the -llib argument.
Example:
-L/usr/X11R6/lib -lX11
means that the linker will look for libX11.so in /usr/X11R6/lib
(...and in other default places.)

GNU make is adding white space after -I (shared directory) option

I'm trying to use armclang compiler through a GNU makefile, but there is a clash between both tools when using -I option.
For armclang compiler, the -I means "Adds the specified directory to the list of places that are searched to find included files.Syntax -Idir" without a space.
For GNU makefile ‘-I dir’ has the same meaning (but with a space).
in My makefile I have the following:
$(aarch32_bootobj): %.o: %.s
#echo " [ASM ] $<"
#armclang --target=armv8a-arm-none-eabi -Icommon/shared -c $< -o $#
When Running the Makefile, I'm getting the following Warning and Error :
armclang: warning: argument unused during compilation: '-I common/shared'
aarch32/shared/bootcode.s:32:10: error: Could not find include file 'boot_defs.hs'
Where boot_defs.hs exists under common/shared
When running the same armclang command outside the makefile, it works. therefore I'm assuming that makefile has formatted the -Icommon/share option and added automatic space just after the -I.
Is there any way to run the armclang command correctly? in other worlds, is it possible to let the makefile parse the -Icommon/shared without any automatic formatting?
I have been trying a lot of tricks to workaround that without any success.
Thanks a lot In advance.
GNU make doesn't split the -Icommon/shared option, and even if it did armclang would be able to parse that. If you remove the # from the armclang call in the Makefile, you'll see exactly what make does and that the -Icommon/shared parameter remains intact.
Your problem is with armclang; see this bug on the tracker. It doesn't pass -I flags to its integrated assembler. A workaround, then, should be to pass -no-integrated-as to armclang:
#armclang -no-integrated-as --target=armv8a-arm-none-eabi -Icommon/shared -c $< -o $#
If that doesn't work, replace the .include directive with #include and either rename your asm files to .S (upper-case S), which indicates that they need C preprocessing, or pass armclang the -x assembler-with-cpp flag. The behavior of this is documented here.

Categories

Resources