Probing language features - fortran

How do I find out at “compile time” (e.g. using the preprocessor) if the compiler supports a particular language feature? The concrete example I am thinking of is the NEWUNIT specifier of Fortran 2008. I would like to do something like this:
#ifdef HAVE_NEWUNIT
! go ahead and use that
#else
! activate workaround
#endif
I am tagging this question fortran because that is what I am concerned with at the moment, though I suspect a general answer may have to go beyond Fortran (autoconf??). Of course, the solution should work with as many compilers as possible, but mostly, I care about gfortran and ifort (both of which have introduced NEWUNIT semi-recently).
Clarification:
I am looking for an automatic way to handle such a situation. (Which might include more than just a Fortran source file -- Makefiles …)
I do not care very much if it is “standard” as long as it would work on most Unix-type systems.

If you are going to go down the route of using autotools, specifically autoconf the following would be how I'd code it all up.
Create the configure.ac:
dnl -*- Autoconf -*-
dnl Process this file with autoconf to produce a configure script.
dnl
AC_PREREQ(2.61)
AC_INIT([test], [0.0.1], [me#example.com])
# Define our M4 macro directory
AC_CONFIG_MACRO_DIR([m4])
# Put our generated config header in the source directory
AC_CONFIG_HEADERS([src/config.h])
# Make sure we have a fortran compiler
AC_PROG_FC([ifort xlf pgfortran gfortran])
AC_LANG([Fortran])
AC_FC_FREEFORM
# Check for newunit option to open()
AX_F08_NEWUNIT
AC_OUTPUT
Create the ax_f08_newunit.m4 macro in the m4/ sub-directory. Since this is where I specified the macros are in configure.ac:
AC_DEFUN([AX_F08_NEWUNIT], [
AC_REQUIRE([AC_PROG_FC])
AC_LANG_PUSH([Fortran])
AC_MSG_CHECKING([for NEWUNIT support])
AC_COMPILE_IFELSE([
program conftest
integer :: i
open(newunit=i,file='test')
end program conftest],
[ax_f08_newunit=yes], [ax_f08_newunit=no])
AC_LANG_POP([Fortran])
if test "x$ax_f08_newunit" = "xyes"; then
AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_NEWUNIT], [1], [NEWUNIT support])
else
AC_MSG_RESULT([no])
fi
])
Then follow all the usual autotools routines:
aclocal -I m4
autoheader
autoconf
Then you can run ./configure, this is my output:
checking for Fortran compiler default output file name... a.out
checking whether the Fortran compiler works... yes
checking whether we are cross compiling... no
checking for suffix of executables...
checking for suffix of object files... o
checking whether we are using the GNU Fortran compiler... no
checking whether ifort accepts -g... yes
checking for Fortran flag needed to allow free-form source... -FR
checking for NEWUNIT support... yes
configure: creating ./config.status
config.status: creating src/config.h
Finally in your src/config.h file you should have:
/* src/config.h. Generated from config.h.in by configure. */
/* src/config.h.in. Generated from configure.ac by autoheader. */
/* NEWUNIT support */
#define HAVE_NEWUNIT 1
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "me#example.com"
/* Define to the full name of this package. */
#define PACKAGE_NAME "test"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "test 0.0.1"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "test"
/* Define to the version of this package. */
#define PACKAGE_VERSION "0.0.1"
Of course your source code has to be run through a preprocessor now too. For example src/test.F90:
program test
#include "config.h"
integer :: i
#ifdef HAVE_NEWUNIT
open(newunit=i,file='data')
#else
i = 7
open(unit=i,file='data')
#endif
end program test
When compiling the test program ifort understands that the capital F means the file needs to be preprocessed.

(Standard) Fortran doesn't really have the facility to do what you want. Most (?) of us (Fortran programmers) would test the availability of a new feature by compiling a code which used it and studying the compiler messages. We might, also, consult compiler documentation.
Fortran preprocessors, which are not defined by the Fortran standard, are, in my experience, usually C preprocessors which have been taught enough about Fortran to be almost usable; think of teaching a dog to walk on two legs, it's never going to be truly bipedal and it's perfectly good at quadripedal locomotion so what's the point ?
Leaving my own prejudices aside for a moment, there is no standard way to check, at compile-time, the availability of a new feature other than by trying to compile a code which uses it.
There was a Technical Report on Conditional Compilation for Fortran back in the 90s (I think) but the extensions to the language it proposed have not found their way into more recent editions of Fortran.
In response to OP's clarification:
One approach would be to follow the lead of a lot of Linux software and to use tools such as automake and autoconf to first determine the capabilities of the (in this case) Fortran compiler, and later to either write (perhaps using a macro-processor) or to select the necessary fragments of code and thereby to construct a compilable program. In other words, configure, make and install.
Since it is far from trivial to determine at compile time what unit numbers might be in use when a new one is needed at run time I suppose you'd have to fall back on the old-fashioned approach of selecting new unit numbers from a pre-defined range which you know (or, if the code is sufficiently large and complex, just hope) is not already in use.

Related

Does C++17 provide a cross-platform scheme to record compiler version and options like Fortran?

Question
Modern Fortran offers a few cross-platform mechanisms to record the compiler version and settings used to build an application. What methods does C++17 have to capture this information? The book by Horton and Van Weert, Beginning C++17, does not appear to address this question.
The Fortran tools are surveyed below.
1. Access to compiler versions and options
The iso_fortran_env in Fortran provides a standard way to access the compiler version and settings used to compile a code. A sample snippet follows.
Code sample
program check_compiler
use, intrinsic :: iso_fortran_env, only : compiler_options, compiler_version
implicit none
write ( *, 100 ) "compiler version = ", compiler_version ()
write ( *, 100 ) "compiler options = ", trim ( compiler_options () )
100 format ( A, A, / )
stop "normal termination . . ."
end program check_compiler
Sample output
$ gfortran -o check_compiler check_compiler.f08
$ ./check_compiler
compiler version = GCC version 8.0.0 20170604 (experimental)
compiler options = -fPIC -mmacosx-version-min=10.12.7 -mtune=core2
STOP normal termination . . .
2. Probing and interacting with host OS
Fortran commands like execute_command_line, get_command, and get_environment_variable offer another route to record information at compile time.
What methods does C++17 have to capture this information?
None. The C++ standard does not even recognize the concept of "compiler" or "options"; there is merely the "implementation".
Furthermore, it would not really make sense, as different C++ files linked into the same program can be compiled with different options. And I'm not just talking about DLL/SOs; you can in theory statically link files that were compiled with different options or even different compiler versions.
Different compilers have ways to specify what version they are through macros. But each one has its own way to report this.
Searching the C++20 standard draft, which is available in GitHub, I find no results for closely-localted "compiler" and "version", nor have I found something like this looking at the text of the standard.
C++20 is at this time still very close to C++17, and certainly such a mechanism has not been removed, so I think it's pretty safe to say that there's no such thing in C++20.
Each compiler injects their own preproxessor tokens indicating itmwas compiled by them, and what version. These tokens are cross platform on compilers that compile on and to kore than one platdorm, such as icc, gcx and clang.
There are now standard defined ways to detect the existence of some srd header files. Boost has extensive headers that decode compiler capabilities based of a myriad of techniques.
__cplusplus in theory is defined to the standard version, but compilers lie.
The language standard specifies macros __cplusplus that encode the version of the standard that the compiler claims to support. It expands to 201703L on a C++17 compiler, 201710L on a C++14 compiler, and so on. It might also define _STDC and _STDC_VERSION. Beyond that, everything is a vendor-specific extension that you should look up in your compiler's manual.
Some but not all compilers, including GCC and Clang, predefine a macro named __VERSION__ that expands to a string describing the compiler version. You can check for this with #ifdef. Beyond that, many compilers contain macros that expand to version numbers, which you can stringify and concatenate. However, be aware that some compilers treat these as compatibility tests, and will claim to be a different compiler if you ask. In addition to its own version numbers, Clang defines __GNUC__, __GNUC_VERSION__ and __GNUC_PATCHLEVEL__ to indicate its compatibility with GCC, and the Windows version will also define _MSC_VER, _MSC_FULL_VER and so on in its Microsoft-compatiblity mode.
You could therefore create a complicated set of nested #elif blocks to recognize various compilers' version macros, but it could never be complete or forward-compatible.

How to enforce single threaded build in source code

Background: I create many small utilities for some very specialised data processing. Often, I am the only user. I don't even think about multi-threaded programming, because the run-time performance is by far sufficient for my use cases. The critical resource is my programming time. So I want to avoid any extra effort required for multi-threaded programming.
However, it seems there is a risk, that my source code gets executed in a multi-threaded context, when I reuse my code in future.
According to CppCoreGuidelines :
Be careful: there are many examples where code that was “known” to
never run in a multi-threaded program was run as part of a
multi-threaded program. Often years later. Typically, such programs
lead to a painful effort to remove data races. Therefore, code that is
never intended to run in a multi-threaded environment should be
clearly labeled as such and ideally come with compile or run-time
enforcement mechanisms to catch those usage bugs early.
Most of the suggestions in the same source actually get me started with multi-threaded programming. The one suggestion, which I prefer to follow says:
Refuse to build and/or run in a multi-threaded environment.
So my question is, how do I do that? E.g. is there an include file, #pragma or so to ensure single threaded build / execution of everything within a source file?
With g++/gcc compiling and linking multithreaded code requires using -pthread compiler and linker option. This option sets _REENTRANT macro which you can inspect at compile time:
$ c="g++ -E -dD -xc++ /dev/null"
$ diff <($c) <($c -pthread)
389a390
> #define _REENTRANT 1
Contrary to popular belief, using -lpthread linker option is unnecessary and insufficient to correctly build a multi-threaded program.
Microsoft Visual Studio sets _MT macro for a multi-threaded build, IIRC.
Boost library does the following:
// Turn on threading support if the compiler thinks that it's in
// multithreaded mode. We put this here because there are only a
// limited number of macros that identify this (if there's any missing
// from here then add to the appropriate compiler section):
//
#if (defined(__MT__) || defined(_MT) || defined(_REENTRANT) \
|| defined(_PTHREADS) || defined(__APPLE__) || defined(__DragonFly__)) \
&& !defined(BOOST_HAS_THREADS)
# define BOOST_HAS_THREADS
#endif
So that you can #include <boost/config.hpp> and then inspect the value of BOOST_HAS_THREADS macro.
The following causes a compilation error if it is built in multi-threaded mode:
#if defined(BOOST_HAS_THREADS) || defined(_REENTRANT) || defined(_MT)
#error This code is single-threaded only.
#endif

Stringify macro with GNU gfortran

How can I stringify a preprocessor macro with GNU gfortran? I would like to pass a macro definition to GNU gfortran which will then be used as a string in the code.
Effectively I would like to do this:
program test
implicit none
character (len=:), allocatable :: astring
astring = MYMACRO
write (*, *) astring
end program test
and then build with:
gfortran -DMYMACRO=hello test.F90
I tried creating various macro, for example:
#define STRINGIFY_(x) #x
#define STRINGIFY(x) STRINGIFY_(x)
...
astring = STRINGIFY(MYMACRO)
but this doesn't work with the gfortran preprocessor.
I also tried using a different style of macro:
#define STRINGIFY(x) "x"
...
astring = STRINGIFY(MYMACRO)
but this just creates a string containing the text 'MYMACRO'.
I then tried changing the macro definition to:
-DMYMACRO=\"hello\"
but this caused unrelated problem in the build process.
Thank you for your help
Your attempt to use the well-known stringification recipe of the C preprocessor,
viz:
#define STRINGIFY_(x) #x
#define STRINGIFY(x) STRINGIFY_(x)
fails for two reasons, each sufficient by itself.
First and simplest, the source file in which you attempt to employ it apparently
has the extension .f90. What this extension signifies to gfortran (and to
the GCC compiler driver, by any other name) is: Free form Fortran source code that should not be preprocessed.
Similarly .f95, .f03 and .f08. If you want gfortran to infer that a source
file contains free form Fortran code that must be preprocessed, give it one of
the extensions .F90, .F95, .F03 or .F08. See the GCC documentation of
these points
Even if you do that simple thing, however, the second reason bites.
The use of the C preprocessor to preprocess Fortran source is as old as C
(which though old, is much younger than Fortran). gfortran is obliged not
to break ancient working code; so, when it invokes the C preprocessor,
it invokes it in traditional mode. The traditional mode of the C preprocessor
is the way in which the preprocessor behaved prior to the first standardization
of the C language (1989), insofar as that unstandardized behaviour can be pinned down. In traditional
mode, the preprocessor does not recognize the stringizing operator '#', which was
introduced by the first C Standard. You can verify this by invoking the preprocessor
directly like:
cpp -traditional test.c
where test.c contains some attempt to employ the stringification recipe. The
attempt fails.
You cannot coax gfortran on its own to work the the stringification recipe.
But there is a workaround. You can invoke cpp directly, unencumbered by traditional mode,
to preprocess the Fortran source in which you want the stringification done and relay its
output to gfortran. If you already know this and were looking for a gfortran-alone
solution you need read no further.
Doing the stringification in your test source this way would look like:
cpp -std=c89 '-DSTRINGIFY_(x)=#x' '-DSTRINGIFY(x)=STRINGIFY_(x)' '-DMYMACRO=STRINGIFY(hello)' test.f90
The output of that is:
# 1 "test.f90"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "test.f90"
program test
implicit none
character (len=:), allocatable :: astring
astring = "hello"
write (*, *) astring
end program test
And that output is what you want to to compile. You could accomplish that as well by:
cpp -std=c89 '-DSTRINGIFY_(x)=#x' '-DSTRINGIFY(x)=STRINGIFY_(x)' \
'-DMYMACRO=STRINGIFY(hello)' test.f90 > /tmp/test.f90 \
&& gfortran -o test /tmp/test.f90
Then you will find that ./test exists and that executing it outputs hello.
You can eliminate the intermediate temporary file with further refinement. Your F90 source
code will compile as F95, as the latter is conservative of the former. So you can take
advantage of the fact that GCC will compile source piped to its standard input if
you tell it what language you are piping, using its -x language option. The
Fortran dialects that you may specify in this way are f77, f77-cpp-input, f95
and f95-cpp-input, where the -cpp-input prefix denotes that
the source is to be preprocessed and its absence denotes that it is not. Thus
cpp -std=c89 '-DSTRINGIFY_(x)=#x' '-DSTRINGIFY(x)=STRINGIFY_(x)' \
'-DMYMACRO=STRINGIFY(hello)' test.f90 | gfortran -x f95 -o test -
works as well as the previous solution, minus the temporary file, and emits
the innocuous warning:
Warning: Reading file '<stdin>' as free form
(Note and retain the final - on the commandline. That is what tells gfortran to
compile the standard input.). The meaning of -x f95 brings the additional
economy that the source, which is preprocessed by cpp, is not preprocessed
again by the compiler.
The use of the option -std=c89 when invoking cpp calls for a cautionary
explanation. It has the effect of making cpp conform to the earliest C Standard.
That is as close to -traditional as we can get while still availing of the
#-operator, on which the stringification recipe depends, But with it you embrace
the possibility of breaking some Fortran code if you preprocess it this way;
otherwise gfortran itself would not enforce -traditional. In the case of
your test program, you could safely omit -std=c89, allowing cpp to conform
to the default C standard when it was built. But if you permit it or direct it
to conform to -std=c99 or later, then the standard will mandate recognition
of // as the beginning of a one-line comment (as per C++), by which any line
of Fortran that contains the concatenation operator will be truncated at the
first occurrence.
Naturally, if you use are using make or another build system to build the
code in which you want the stringified macros, you will have a way of telling
the build system what actions constitute compiling a given class of compilable
files. For any Fortran source file fsrc you wanted to compile with
a stringification preamble, the actions to specify would be in the vein:
cpp -std=c89 '-DSTRINGIFY_(x)=#x' '-DSTRINGIFY(x)=STRINGIFY_(x)' \
'-DMYMACRO=STRINGIFY(hello)' fsrc.f90 | gfortran -x f95 -c -o fsrc.o -
Although this is an old and answered question, I wanted to achieve macro stringification in gfortran without changing the default preprocessor or build process. I found that the preprocessor would do what I want, as long as there was no initial quotation mark on the line, therefore the desired stringification can be achieved by breaking lines with ampersands:
astring = "&
&MYMACRO"
A caveat is that this really only works with the traditional preprocessor, and for examples breaks with intel ifort compiler, which is too smart to fall for this trick. My current solution is to define separate stringification macros for gfortran as:
#ifdef __GFORTRAN__
# define STRINGIFY_START(X) "&
# define STRINGIFY_END(X) &X"
#else /* default stringification */
# define STRINGIFY_(X) #X
# define STRINGIFY_START(X) &
# define STRINGIFY_END(X) STRINGIFY_(X)
#endif
program test
implicit none
character (len=:), allocatable :: astring
astring = STRINGIFY_START(MYMACRO)
STRINGIFY_END(MYMACRO)
write (*, *) astring
end program test
It looks really ugly, but it does get the job done.
Removing the quotes around x in STRINGIFY solved the problem for me:
#define STRINGIFY(x) x ! No quotes here
program test
implicit none
character (len=:), allocatable :: astring
astring = STRINGIFY(MYMACRO)
write(*,*), astring
end program test
Compiled with
gfortran -cpp -DMYMACRO=\"hello\" test.f90
The -cpp option enables the preprocessor for all extensions.

Building OpenSSL under Borland C++ Builder, Win 8.1

I'm following the instructions from INSTALL.W32 (various OpenSSL versions), in general it's:
* Configure for building with Borland Builder:
> perl Configure BC-32
* Create the appropriate makefile
> ms\do_nasm
* Build
> make -f ms\bcb.mak
Now, I do get two kind of errors when trying to build:
For OpenSSL < 1.0.0
nasmw -f obj -d__omf__ -ocrypto\md5\asm\m5_win32.obj .\crypto\md5\asm\m5_win32.asm
'nasmw' is not recognized as an internal or external command,
operable program or batch file.
Otherwise
Warning W8017 C:\CBuilder5\Include\sys/stat.h 34: Redefinition of 'S_IFMT' is not identical
Warning W8017 C:\CBuilder5\Include\sys/stat.h 35: Redefinition of 'S_IFDIR' is not identical
Error E2227 .\crypto\rand\randfile.c 226: Extra parameter in call to _open in function RAND_write_file
Warning W8053 .\crypto\rand\randfile.c 262: '_chmod(const signed char *,int,...)' is obsolete in function RAND_write_file
*** 1 errors in Compile ***
Yes, I feel bad for using Borland C++ Builder 5 but I can't do anything about it, and yes, I consider the Shining Light option if everything else fails.
I do not use OpenSSL but from your text some hints:
NASM
is not default assembler for Borland compilers
you need to download and install it first
(it is for free and one of the best compilers I used in the past)
you are missing some #define before including OpenSSL or including in wrong order
that is why you have the first warnings and most likely also the error
some libs need to add configuration #defines (added by some specific IDE's)
to specify what compiler,platform,endianess... is used
before any includes
usually if you include in wrong order then the defines are defined for some instances of a lib file but not for all
so try to reorder the includes
sometimes helps to include before the lib some other thing like conio,stdio,windows,...
to determine which define is missing or wrong open the stat.h
and look for #ifdef #ifndef statements around S_IFMT
The solution for the newest version (1.0.2d) was to:
remove the extra parameter from randfile (which, as comment stated, was unnecessary),
edit ms\bcb.mak, search for -DMD5_ASM -DSHA1_ASM -DRMD160_ASM
and change to -DMD5_NO_ASM -DSHA1_NO_ASM -DRMD160_NO_ASM . (there was an unresolved external error with SHA, MD5 and RMD160, they basically couldn't be compiled in asm).
There were some other steps included as well, but they're just specific to my environment.

How to tell if glibc is used

I am trying to implement backtrace functionality for a large framework, which is used for different platforms and OS'es. In some of them, it is linked against glibc, while in the other, something different (eg. uclibc) is used. backtrace() function exists only in the former.
Is there any way to tell whether glibc is used? Any #define? I was unable to find an answer in glibc manual. I know I can't have linking-time information during compilation, but I guess include files have to differ. At least backtrace have to be declared somewhere.
I would like to check it without being forced to pass explicit flags to the compiler.
Include features.h, it contains the macros you need, e.g.
#define __GNU_LIBRARY__ 6
/* Major and minor version number of the GNU C library package. Use
these macros to test for features in specific releases. */
#define __GLIBC__ 2
#define __GLIBC_MINOR__ 4
There are the #defines __GNU_LIBRARY__, __GLIBC__ and __GLIBC_MINOR__ (6, 2 and 11 on my system with glibc-2.11) in features.h.
Checking for preprocessor macros is not a good solution. uClibc and possibly other libc implementations define macros to mimic glibc (without providing all of its bloated functionality) for much the same reasons that all browsers include "Mozilla" in their User-Agent strings: broken programs that expect to see glibc and turn off lots of features if they don't see it.
Instead you should write a configure script to probe for backtrace and use it only if it's available.
Empirically, both of the following compile and run fine on GCC 6.4:
#include <stdio.h>
int main(void) {
#ifdef __GLIBC__
puts("__GLIBC__");
#endif
return 0;
}
and:
int main(void) {
#ifdef __GLIBC__
puts("__GLIBC__");
#endif
return 0;
}
but only the first produces output of course.
This must mean that __GLIBC__ comes from stdio.h which must include features.h, see also: What is the purpose of features.h header?
Therefore, strictly speaking, __GLIBC__ by itself is not a clear indication that glibc is used, since even without headers, GCC already embeds runtime objects such as crt1.o in the finale executable, and those come from glibc.
So the main missing question is: does glibc guarantee that features.h gets included by every header? I could not find a clear documentation quote. TODO.
#if defined(__GLIBC__) && !defined(__UCLIBC__) && !defined(__MUSL__)
This is getting a bit ugly and syntactically ambiguous, but useful.