i386 macro predefined in make or gcc? - gcc

I've been attempting to make a folder for each architecture my code can support. In this folder are platform specific files to include. I include them as follows:
#define STR(x) #x
#define ASSTR(x) STR(x)
#include ASSTR(ARCHITECTURE/sizes.h)
My compilation line in make looks like this:
gcc -o $# -c $< -DARCHITECTURE=i386
Which works, until I define ARCHITECTURE to be i386. When this happens, it looks for 1/sizes.h, so I assume it's already defined somewhere.

I believe the C preprocessor (cpp), which is called by gcc, defines i386 (for i386 systems). You can find out what it defines like so:
touch foo.h; cpp -dM foo.h; rm foo.h
This method is described by the cpp man page, under -d, with the character M (so, -dM):
Instead of the normal output, generate a list of #define directives for all the macros defined during the execution of the preprocessor, including predefined macros. This gives you a way of finding out what is predefined in your version of the preprocessor. Assuming you have no file foo.h, the command
touch foo.h; cpp -dM foo.h
will show all the predefined macros.

Related

gfortran does not process #define in include [duplicate]

I would like to understand how the preprocessor inlines includes into the code in Fortran. With C, it's pretty simple:
Test.c:
#include <stdio.h>
int main(void) {
return 0;
}
Then I compile using:
gcc -E test.c
Then it displays the content generated by the C preprocessor, as expected.
Now assume I have this Fortran code:
Test.f:
program test
include "mpif.h"
call mpi_init
call mpi_finalize
end
Then I run:
gfortran -E -cpp test.f // For some reason I need -cpp when using -E in Fortran
But I won't have the expected result, which is the generated include embedded into the code.
Instead, I have this:
# 1 "test.f"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "test.f"
program test
include 'mpif.h'
call mpi_init
call mpi_finalize
end
What am I doing wrong here?
Fortran has its own include directive which must not be confused with the preprocessor directive #include. As far as I understand it, the included code is not embedded into the master file, but the compiler instead continues to compile from the include file, and returns to the master file at the end of that file. From here:
The INCLUDE statement directs the compiler to stop reading statements
from the current file and read statements in an included file or text
module.
Also, included files are not preprocessed further, while #included ones are.
Note, that there is also a naming convention that enables the preprocessor only on files with capital suffixes *.F and *.F90. If you want to preprocess *.f or *.f90 files, you need to specify that in a compile option, e.g. -cpp for gfortran, and -fpp for ifort.

Does "-Wl,-soname" work on MinGW or is there an equivalent?

I'm experimenting a bit with building DLLs on windows using MINGW.
A very good summary (in my opinion) can be found at:
https://www.transmissionzero.co.uk/computing/building-dlls-with-mingw/
There is even a basic project which can be used for the purpose of this discussion:
https://github.com/TransmissionZero/MinGW-DLL-Example/releases/tag/rel%2Fv1.1
Note there is a cosmetic mistake in this project which will make it fail out of the box: the Makefile does not create an "obj" directory - Either adjust the Makefile or create it manually.
So here is the real question.
How to change the Windows DLL name so it differs from the actual DLL file name ??
Essentially I'm trying to achieve on Windows, the effect which is very well described here on Linux:
https://www.man7.org/conf/lca2006/shared_libraries/slide4b.html
Initially I tried changing "InternalName" and ""OriginalFilename" in the resource file used to create the DLL but that does not work.
In a second step, I tried adding "-Wl,-soname,SoName.dll" on the command that performs the final link, to change the Windows DLL name.
However, that does not seem to have the expected effect (I'm using MingW 7.3.0, x86_64-posix-seh-rev0).
Two things makes me say that:
1/ The test executable still works (I would expect it to fail, because it tries to locate SoName.dll but can't find it).
2/ "pexports.exe AddLib.dll" produces the output below, where the library name hasn't changed:
LIBRARY "AddLib.dll"
EXPORTS
Add
bar DATA
foo DATA
Am I doing anything wrong ? Are my expectations wrong perhaps ?
Thanks for your help !
David
First of all, I would like to say it's important to use either a .def file for specifying the exported symbols or use __declspec(dllexport) / __declspec(dllimport), but never mix these two methods. There is also another method using the -Wl,--export-all-symbols linker flag, but I think that's ugly and should only be used when quick and dirty is what you want.
It is possible to tell MinGW to use a DLL filename that does not match the library name. In the link step use -o to specify the DLL and use -Wl,--out-implib, to specify the library file.
Let me illustrate by showing how to build chebyshev as a both static and shared library. Its sources consist of only only 2 files: chebyshev.h and chebyshev.c.
Compile
gcc -c -o chebyshev.o chebyshev.c -I. -O3
Create static library
ar cr libchebyshev.a chebyshev.o
Create a .def file (as it wasn't supplied and __declspec(dllexport) / __declspec(dllimport) wasn't used either). Note that this file doesn't contain a line with LIBRARY allowing the linker to specify the DLL filename later.
There are several ways to do this if the .def file wasn't supplied by the project:
3.1. Get the symbols from the .h file(s). This may be hard as sometimes you need to distinguish for example between type definitions (like typedef, enum, struct) and actual functions and variables that need to be exported;
echo "EXPORTS" > chebyshev.def
sed -n -e "s/^.* \**\(chebyshev_.*\) *(.*$/\1/p" chebyshev.h >> chebyshev.def
3.2. Use nm to list symbols in the library file and filter out the type of symbols you need.
echo "EXPORTS" > chebyshev.def
nm -f posix --defined-only -p libchebyshev.a | sed -n -e "s/^_*\([^ ]*\) T .*$/\1/p" >> chebyshev.def
Link the static library into the shared library.
gcc -shared -s -mwindows -def chebyshev.def -o chebyshev-0.dll -Wl,--out-implib,libchebyshev.dll.a libchebyshev.a
If you have a project that uses __declspec(dllexport) / __declspec(dllimport) things are a lot easier. And you can even have the link step generate a .def file using the -Wl,--output-def, linker flag like this:
gcc -shared -s -mwindows -o myproject.dll -Wl,--out-implib,myproject.dll.a -Wl,--output-def,myproject.def myproject.o
This answer is based on my experiences with C. For C++ you really should use __declspec(dllexport) / __declspec(dllimport).
I believe I have found one mechanism to achieve on Windows, the effect described for Linux in https://www.man7.org/conf/lca2006/shared_libraries/slide4b.html
This involves dll_tool
In the example Makefile there was originally this line:
gcc -o AddLib.dll obj/add.o obj/resource.o -shared -s -Wl,--subsystem,windows,--out-implib,libaddlib.a
I simply replaced it with the 2 lines below instead:
dlltool -e obj/exports.o --dllname soname.dll -l libAddLib.a obj/resource.o obj/add.o
gcc -o AddLib.dll obj/resource.o obj/add.o obj/exports.o -shared -s -Wl,--subsystem,windows
Really, the key seems to be the creation with dlltool of an exports file in conjunction with dllname. This exports file is linked with the object files that make up the body of the DLL and it handles the interface between the DLL and the outside world. Note that dlltool also creates the "import library" at the same time
Now I get the expected effect, and I can see that the "Internal DLL name" (not sure what the correct terminology is) has changed:
First evidence:
>> dlltool.exe -I libAddLib.a
soname.dll
Second evidence:
>> pexports.exe AddLib.dll
LIBRARY "soname.dll"
EXPORTS
Add
bar DATA
foo DATA
Third evidence:
>> AddTest.exe
Error: the code execution cannot proceed because soname.dll was not found.
Although the desired effect is achieved, this still seems to be some sort of workaround. My understanding (but I could well be wrong) is that the gcc option "-Wl,-soname" should achieve exactly the same thing. At least it does on Linux, but is this broken on Windows perhaps ??

How to use a static library's module in Fortran program depending on Makefile's configuration [duplicate]

This question already has an answer here:
Conditional compilation in gfortran
(1 answer)
Closed 4 years ago.
I'm importing the following module (from an static library) in a file named initprogram.f90 this way:
use device_info
However I only want to include this library when this option in the Makefile is selected:
ifeq ($(strip $(WITH_GPU)),1)
(When WITH_GPU is equal to 1). If I'm not using a GPU, device_info.mod should not be available, since I don't need it. How can I do that?
Basically I want to get rid of this error:
Fatal Error: Can't open module file 'device_info.mod' for reading at (1): No such file or directory
When compiling without the library where device_info.mod is defined.
You probably need:
A preprocessor to hide or not the use device_info declaration in your Fortran source file, depending on an option you pass to it. Do you have a preprocessor in your Fortran compilation chain? If yes do you know how to pass it options from the command line and how to use them in your source file to hide or not parts of your code?
Pass the right option to the compiler chain from your Makefile.
Let's assume you do have a preprocessor and it has an #ifdef - #endif macro. Let's also assume your compiler chain takes options -D MACRO=VALUE from the command line. And let's assume the syntax of your compiler command looks like:
<compiler-name> <options> <source-file> -o <binary-output-file>
Just edit your source file and add:
#ifdef WITH_GPU
use device_info
#endif
And then, edit your Makefile:
COMPILER := <whatever-compiler-you-use>
COMPILER_FLAGS := <whatever-compiler-options-you-need-by-default>
OTHER_DEPENDENCIES := <whatever-default-dependencies>
ifeq ($(strip $(WITH_GPU)),1)
COMPILER_FLAGS += -D WITH_GPU=1
OTHER_DEPENDENCIES += device_info.mod
endif
initprogram.exe: initprogram.f90 $(OTHER_DEPENDENCIES)
$(COMPILER) $(COMPILER_FLAGS) $< -o $#
(the $< and $# make automatic variables expand respectively to the first prerequisite (initprogram.f90) and the target (initprogram.exe) of the rule).

how to gcc compile with #define in multiple files

I have a project with multiple files.. I want to compile it using gcc from command line.
the directory looks like this
lib/
Comp/ contains .cpp files
Decomp/ contains .cpp files
Globals.cpp
include/
Comp/ contains .h files
Decomp/ contains .h files
Globals.h
some of these .h files are not paired with .cpp files
to compile this i use something like this :
g++ lib/Comp/* lib/Decomp/* lib/Globals.cpp -std=c++0x -o TEST
the problem is,I have to add some #defines for each .h file and i have to do it through command line. how to do this ??
also if i had to compile each file on its own and then link them. what would be the appropriate order for doing this ?
The dirtiest ugliest way is that you want to use something like:
g++ -Iinclude lib/Comp/*.cpp lib/Decomp/*.cpp lib/Globals.cpp -o test
Your .cpp files should #include <Comp/foo.h> or whatever
The correct way to manage this is to use a makefile to build each object file and then link them together:
Makefile
Create a a file called Makefile and put the following in it:
CXX=g++
CPPFLAGS=-Iinclude -DFOO -DBAR=1 -DSOME_STRING=\"My Name\"
CXXFLAGS=-O2 -g
SOURCES=lib/Comp/file1.cpp \
lib/Comp/file2.cpp \
lib/Comp/file3.cpp \
lib/Decomp/file1.cpp \
lib/Decomp/file2.cpp \
...
OBJ=$(SOURCES:%.cpp=%.o)
default: test
test: $(OBJ)
<tab> $(CXX) -o $# $(OBJ)
%.o: %.cpp
<tab> $(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $# -c $<
NOTES
Replace file1.cpp etc. with the actual filenames in your project. DO NOT include headers in SOURCES only your .cpp or .cc files
If you are using sub-paths like #include <Comp/foo.h> or #include "Comp/foo.h" in your source files then you only need to use -Iinclude in CPPFLAGS but if you are doing something like "foo.h" and foo.h is actually in include/Comp/ then add -Iinclude/Comp and -Iinclude/Decomp to the CPPFLAGS
Where it says <tab> make sure you use the TAB key to insert a tab (don't type the word '')
Before using this Makefile blindly . Know that it will NOT work as is you have to correct the entries. It is offered as a starting point... Read up on writing Makefiles ... http://frank.mtsu.edu/~csdept/FacilitiesAndResources/make.htm has a good introduction
Defines can be provided on the compiler command line using -DVAR=VALUE (on Windows, presumably /DVAR=VALUE). Note that you can not provide different defines for different headers as in:
compiler -DX=one first.h -DX=two second.h third.cc -o third.o
In such a case, my compiler spews warning and uses the last value of X for all source code.
Anyway, in general you should not list header files on the compilation line; prefer to include them from the implementation files (.cc/.cpp or whatever) that need them.
Be careful too - if you're changing defines to modify class definitions, inline function implementation etc. you can end up with technically and/or practically undefined behaviour.
In terms of how best to decide which objects to create and link - you probably want one object per .cc/.cpp file. You can link those objects then specify them on the command line when compiling the file containing main().

compiler directive for compiling on different platforms

I am compiling a demo project.
The project is written for windows and linux. I have written a Makefile. However, I am not sure how to specify the platform the compiler will be compiling on.
I will be compiling on Linux.
In my source file I have this:
#if defined(WIN32)
#include ...
#include ...
#elif defined(LINUX)
#include ...
#include ..
#else
#error "OS not supported"
#endif
My simple Makefile is this. And when I compile I get the error "OS not supported".
How can I add the directive so that it will compile with the #elif defined(LINUX).
LIBS_PATH = -L/usr/norton/lib
INC_PATH = -I/usr/norton/include
LIBS = -lntr
app: *.cpp *.h Makefile
g++ $(LIBS_PATH) $(INC_PATH) *.cpp -o app
Many thanks for any suggestions,
Decide which is going to be your default platform - say LINUX.
LIBS_PATH = -L/usr/norton/lib
INC_PATH = -I/usr/norton/include
LIBS = -lntr
PLATFORM = -DLINUX
CXX = g++
app: *.cpp *.h Makefile
${CXX} ${CFLAGS} ${PLATFORM} ${INC_PATH} *.cpp -o $# ${LIBS_PATH} ${LIBS}
You can use round brackets in place of braces. This uses a macro for the C++ compiler, allows you to add other flags via CFLAGS (though that is also usually set by 'make'), and adds a platform, the include path, the library path and the actual library to the compile line.
Note that your rule enforces a complete recompilation of everything every time anything changes. This is 'safe' but not necessarily efficient. Note that wild-cards are dangerous too - more so for the source than the headers. You may include that backup copy of a file in the build (old-reader.cpp - you only wanted reader.cpp in there really). More conventionally, you list the object files needed for the program so that each object file can be individually rebuilt when needed, and the results linked together. If you get your dependencies correct (a moderately big 'if'), then there's no problem. If you get them wrong, you can end up with inconsistent programs.
However, if the difference is between a 5 second recompile and a 5 minute recompile, you should probably take the 5 minute recompilation (as shown) and answer another SO question while waiting.
To compile on Linux (64-bit):
make CFLAGS="-m64"
To compile on Linux (32-bit):
make CFLAGS="-m32"
To compile on Windows 64:
make PLATFORM=-DWIN64
To compile on Windows 32:
make PLATFORM=-DWIN32
Etc.
You can add -DLINUX=1 when compiling.
Also, if you run:
echo "" | cpp -dD
You can see the list of default #define when compiling. In linux, there will always be a:
#define __linux__ 1
in the output. So if you change your LINUX by the above #define, you don't need to do anything special. Ie:
...
#elif defined(__linux__)
...
As for the Makefile itself, I would do something like:
CXX=g++
CPPFLAGS = -I/usr/norton/include
LDFLAGS = -L/usr/norton/lib -lntr
OBJ_FILES = one.o two.o
app: $(OBJ_FILES) Makefile
one.o: one.cpp one.h
two.o: two.cpp two.h
So the implicit rules are used.

Resources