An alternative to Fortran CPP-like preprocessors - fortran

I'm looking for an alternative to #ifdef #else #enddef in my Fortran 90 code.
Is there another way to control what use statements are executed when a module is called? I want to get away from #include files in my complex system.
For example, this is what I have now.
#include "defs.h"
module X
#ifdef Sys
use ....
#else
use ....
#endif
implicit none
snip...
#ifdef Sys
some block of code...
#else
some block of code...
#endif
end module X
In defs.h Sys is defined. I would like find an alternative to using defs.h to control the #ifdef.... parts of the code.
Appreciate any thoughts on this.

I'll start off by repeating what was noted in the comments: The correct solution to your real problem is really to work out why when using FCM the compiler can't find the file you wish to include.
To fix your specific problem, due to not being able to successfully include a given file that provides various definitions we can instead define symbols through arguments passed to the compiler.
Consider the following, stored in test.fpp
#ifdef Sys
#warning "This messages tells you Sys is defined"
#else
#warning "This messages tells you Sys is NOT defined"
#endif
program test
implicit none
write(*,'("For clarity we will now print defined if Sys is defined or not defined if Sys is not defined")')
#ifdef Sys
write(*,'("Defined")')
#else
write(*,'("Not defined")')
#endif
end program test
We can compile this using gfortran -ffree-form test.fpp -o test. This will produce:
test.fpp:4:2: warning: #warning "This messages tells you Sys is NOT defined" [-Wcpp]
#warning "This messages tells you Sys is NOT defined"
^
and doing ./test gives the output
For clarity we will now print defined if Sys is defined or not defined if Sys is not defined
Not defined
If we now compile using gfortran -ffree-form test.fpp -o test -DSys we instead see the message
test.fpp:2:2: warning: #warning "This messages tells you Sys is defined" [-Wcpp]
#warning "This messages tells you Sys is defined"
^
and running ./test gives us
For clarity we will now print defined if Sys is defined or not defined if Sys is not defined
Defined

Related

How to use -enable-cxx11 flag in cgo

I am trying to run C++ code inside my go code. I figured out that I need -enable-cxx11 flag during compilation (because otherwise I get an error like here).
But somehow flags do not work:
/*
#cgo CPPFLAGS: -enable-cxx11
#include "cPackage/create_hyper_file_from_csv.cpp"
*/
import "C"
How do I use this flag?

Use emscripten from Clang compiled executable

Is it possible to execute emcc (from emscripten) on a clang compiled executable ?
I tried but the result is:
ERROR root: pdfium_test: Input file has an unknown suffix, don't know what to do with it!
I try that because I'm not able to find a solution to compile PDFium project with emcc, but with clang everything is fine.
The reason is:
Emscripten is a cross-compiler, and therefore the OS-specific macros
of the host system should all be undefined when building C/C++ code.
If you look at tools/shared.py, Emscripten gives special attention to
-U all host-specific flags that Clang may automatically try to add in.
But there is lots of Platform specific code in PDFium, so I get:
#error Sorry, can not figure out target OS. Please specify _FX_OS_ macro.
This macro is defined if the __linux__ macro (for example) is defined, here is the code snippet:
#ifndef _FX_OS_
#if defined(__ANDROID__)
#define _FX_OS_ _FX_ANDROID_
#define _FXM_PLATFORM_ _FXM_PLATFORM_ANDROID_
#elif defined(_WIN32)
#define _FX_OS_ _FX_WIN32_DESKTOP_
#define _FXM_PLATFORM_ _FXM_PLATFORM_WINDOWS_
#elif defined(_WIN64)
#define _FX_OS_ _FX_WIN64_DESKTOP_
#define _FXM_PLATFORM_ _FXM_PLATFORM_WINDOWS_
#elif defined(__linux__)
#define _FX_OS_ _FX_LINUX_DESKTOP_
#define _FXM_PLATFORM_ _FXM_PLATFORM_LINUX_
#elif defined(__APPLE__)
#define _FX_OS_ _FX_MACOSX_
#define _FXM_PLATFORM_ _FXM_PLATFORM_APPLE_
#endif
#endif // _FX_OS_
#if !defined(_FX_OS_) || _FX_OS_ == 0
#error Sorry, can not figure out target OS. Please specify _FX_OS_ macro.
#endif
So, I tried to define manually the __linux__ macro with:
emmake make -j5 BUILDTYPE=Release __linux__=1
... but same error. Maybe it's not the good way ?
Thank you in advance.
EDIT: The answer of JF Bastien helps me a lot. But now I've this build error and I've any idea of what to do. If someone have an idea...
clang-3.7: warning: argument unused during compilation: '-msse2'
clang-3.7: warning: argument unused during compilation: '-mmmx'
error: unknown FP unit 'sse'
EDIT 2: Solution for above problem: remove "-msse2, -mmmx and -mfpmath" flags from v8/build/toolchain.gypi
Porting to Emscripten is the same as porting to any other platform: you have to use that's platform's own platform-specific headers. Some will have nice equivalents, and some won't.
In most cases you'll need to find these chains of platform-specific #if defined(...) and add an #elif defined(__EMSCRIPTEN__), and do the right thing there. That's more complicated than it sounds: you can't do inline assembly, you can't rely on (most) platform-specific headers, ... But in some cases it's easy.
Emscripten has examples which do this, and has a porting guide.
For PDFium in particular, you'll have to avoid all the platform-specific font rendering, any threading-related things, and the sandboxing (security shouldn't be as big of an issue since JavaScript itself is a sandbox). You'll also have to figure out how to do file I/O, and probably want to disable all networking code.
Or you could use other ports of PDFium to Emscripten.

Error "'fdopen' was not declared" found with g++ 4 that compiled with g++3

I have code that compiled happily with g++ version 3.something. I then wanted to build some other code that had C++11 symbols in it so I upgraded to g++ 4.7. Now my original code doesn't build. I get the error:
'fdopen' was not declared in this scope
According to the man page, fdopen() is declared in stdio.h which I am including. I'm not sure it is relevant, but I am working in a Cygwin environment. The exact version of g++ I am using is version 4.7.2 provided by Cygwin.
I have not changed this code since I switched compiler and I can definitely confirm that it built and my test code ran and passed with the previous compiler.
As requested, example code to demonstrate the problem:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char **argv)
{
int fd;
FILE *fp;
fd = open("test.txt", (O_WRONLY | O_CREAT | O_EXCL), S_IRWXU);
if(0 < fd)
{
fp = fdopen(fd, "wb");
fprintf(fp, "Testing...\n");
fclose(fp);
}
return 0;
}
# g++ -std=c++11 -o test test.cpp
test.cpp: In function 'int main(int, char**)':
test.cpp:14:29: error: 'fdopen' was not declared in this scope
Whatever you do, please don't mess with the __STRICT_ANSI__ flag. That symbol is controlled by GCC. You should let GCC define it and leave it alone.
What you are really looking for is the _POSIX_C_SOURCE feature test macro. You see, fdopen is not defined by the C language standard. When you tell GCC that you are writing a C++11 program, then GCC goes into "strict" mode where it tries to not define any functions that are not defined by the language. This is to avoid name collisions with your own code. For instance, a valid C++11 program is free to define its own function named fdopen since fdopen is not a reserved identifier in the language.
But fdopen is defined by POSIX, which is a standard that includes, but is separate from, the C language standard. When writing an application that uses POSIX functions, like fdopen, you must tell the system that you intend to write a POSIX application so that it knows that it should make functions defined by POSIX available to your program. This is where the _POSIX_C_SOURCE feature test macro comes in. At the top of every source file, before inclusion of any header, define this macro to the appropriate value. For instance:
#define _POSIX_C_SOURCE 200112L
The value you should use in the definition depends on which version of POSIX you are targeting. If you are unsure about which version you want to target, you can just target the same version that your host system is compliant with. You can determine this by running getconf from a shell:
$ getconf _POSIX_VERSION
200809L
$ _
Here, my system tells me it is compliant with POSIX version 200809L (i.e. POSIX.1-2008). I can #define _POSIX_C_SOURCE 200809L in my source code and be confident that all standard features supported by my system will be made available to me.
The problem comes from -std=c++11. The fdopen() function is not in ANSI C (only in the POSIX standard), and compiling with -std=c++11 option implies defining __STRICT_ANSI__, which excludes several functions from stdio.h. By the way, in C++ programs, you should normally include <cstdio> instead of <stdio.h>, see here: stdio.h not standard in C++?.
If you need to use fdopen(), you might want to remove the -std=c++11 option when compiling. Another possible soltion, although not really elegant, can be to use this in your source code:
#ifdef __STRICT_ANSI__
#undef __STRICT_ANSI__
#include <cstdio>
#define __STRICT_ANSI__
#else
#include <cstdio>
#endif
(which is intended to work with and without the -std=c++11 option).

Preprocessor directives and #error

I want to show error when someone try to compile my code under other system than WIN32 and LINUX. But this code:
#ifdef WIN32
// Some code here for windows
#elif LINUX
// Some code for linux
#else
#error OS unsupported!
#endif
But this gives me an error:
#error OS unsupported
and compiler doesn't say anything else, just error.
What is wrong?
Two issues here:
your #elif does not test for the mere existence of the symbol, but for its truth (ie. defined and non-zero). You should use #elif defined(...) and, to be consistent, #if defined(...) at the start.
the symbols you are matching for are wrong. You should use, respectively, _WIN32 and __linux__. See this reference for more platforms.
LINUX is not a standard predefined macro. You probably want to check for __linux not LINUX
I know some code checks for _WIN32 but I don't know what's correct on Windows.

C++ command line debug argument

How can I change the value of a boolean macro when I run my program through the command line? For instance, suppose I have the following macro in my cpp file, call it MyCpp.cpp
#define DEBUG 1
How can I change this when I run my program? through the command line:
g++ -Wall -Wextra -o MyCpp MyCpp.cpp
I am pretty sure you specify some kind of command line option, does this ring any bells?
Also, I do NOT want to use argv[]
First, change your source code:
#ifndef DEBUG
# define DEBUG 1
#endif
Now you can say on the command line:
g++ -Wall -Wextra -o MyCpp MyCpp.cpp -DDEBUG=5
# ^^^^^^^^^
The command line argument -DFOO=bar has the same effect as putting #define FOO bar in your source code; you need the #ifndef guard to avoid an illegal redefinition of the macro.
Sometimes people use an auxiliary macro to prevent the definition of another macro:
#ifndef SUPPRESS_FOO
# define FOO
#endif
// ... later
#ifdef FOO
// ...
#endif
Now say -DSUPPRESS_FOO to not define FOO in the code...
How can I change the value of a boolean macro when I run my program through the command line?
As it stands, you can't. You are using a preprocessor symbol so the decision as to whether debug information should be printed is a compile time decision. You are going to have to change that compile-time DEBUG symbol to a run-time variable that you set by parsing the command line, via some configuration file read in at run time, or both.
Parsing the command line isn't that hard. There are plenty of low-level C-style tools to help you do that. Boost has a much more powerful C++ based scheme. The trick then is to change those compile-time debug decisions to run-time decisions. At the simplest, it's not that hard: Just replace that DEBUG preprocessor symbol with a global variable. You can get quite a bit more sophisticated than this of course. Eventually you'll have a configurable logging system. Boost has that, too.
Please note the following. If you have in your c/cpp file or one of your included header files:
#define DEBUG 1
then you cannot modify this definition using the command line of the compiler (makefile). There is simply no chance. The cpp file will simply overwrite the command line setting.