2013-09-06 3 views
1

Как узнать в «время компиляции» (например, с использованием препроцессора), если компилятор поддерживает определенную языковую функцию? Конкретный пример, который я имею в виде это NEWUNIT спецификатора Фортран 2008. Я хотел бы сделать что-то вроде этого:Возможности языка тестирования

#ifdef HAVE_NEWUNIT 
! go ahead and use that 
#else 
! activate workaround 
#endif 

Я разметил этот вопрос fortran, потому что это то, что меня интересует в данный момент, хотя Я подозреваю, что общий ответ, возможно, должен выйти за пределы Фортрана (autoconf ??). Разумеется, решение должно работать с максимально возможным количеством компиляторов, но в основном я забочусь о gfortran и ifort (оба из которых представили недавно NEWUNIT).

Разъяснение:

  1. Ищу для автоматического способ справиться с такой ситуацией. (Который может включать в себя больше, чем просто исходный файл Fortran - Makefiles ...)
  2. Мне все равно, если он «стандартный», если он будет работать на большинстве систем Unix.
+0

Нет такой вещи стандартизованной. –

+0

Если у вас есть доступ к компилятору C, вы можете использовать его для предварительной обработки макросов (gcc -E), а затем использовать компилятор Fortran для компиляции вывода. – cup

+1

Помните, что, поскольку препроцессор Fortran не стандартизирован, большинство компиляторов могут работать только с простейшими макросами. Это нормально для простых '# ifdef''. Но, например, как показано в примере, fpp Intel распознает символ '&' как символ продолжения, тогда как препроцессор gcc менее осведомлен о Fortran и, следовательно, нет. –

ответ

3

Если вы собираетесь спуститься по маршруту использования autotools, в частности autoconf, следующее будет следующим:

Создайте 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], [[email protected]]) 

# 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 

Создание ax_f08_newunit.m4 макроса в m4/ подкаталоге. Так как это, где я указал макросы в 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 

]) 

Далее следуют все обычные autotools процедуры:

aclocal -I m4 
autoheader 
autoconf 

Затем вы можете запустить ./configure, это мой выход:

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 

Наконец, в вашем файле src/config.h вы должны:

/* 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 "[email protected]" 

/* 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" 

Конечно, ваш исходный код также должен быть запущен через препроцессор. Например 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 

При компиляции программы тестирования ifort понимает, что капитал F означает, что файл должен быть предварительно обработаны.

2

(Standard) Fortran не имеет возможности делать то, что вы хотите. Большинство (?) Нас (программистов Fortran) проверили бы наличие новой функции, скомпилировав код, который использовал его и изучил сообщения компилятора. Мы также можем обратиться к документации компилятора.

Препроцессоры Fortran, которые не определены стандартом Fortran, по моему опыту, обычно являются препроцессорами C, которые были достаточно изучены в отношении Fortran, чтобы быть практически пригодными для использования; подумайте о том, чтобы научить собаку ходить на двух ногах, это никогда не будет поистине двуногим, и это отлично подходит для квадрипедальной локомоции, так что в чем смысл?

Оставляя свои собственные предубеждения в стороне на мгновение, нет стандартного способа проверки во время компиляции доступности новой функции, кроме как при попытке скомпилировать код, который ее использует.

В 90-х годах (как мне кажется) был опубликован Технический отчет об условной компиляции для Fortran (но я думаю), но расширения к предложенному ему языку не нашли своего пути в более поздние версии Fortran.

В ответ на разъяснение ФП в:

Один подход должен был бы последовать примеру многих программного обеспечения Linux и использовать такие инструменты, как automake и autoconf сначала определить, с возможностями (в данном случае) Fortran компилятор, а затем либо писать (возможно, используя макропроцессор), либо выбирать необходимые фрагменты кода и тем самым создавать компилируемую программу. Другими словами, configure, make и install.

Поскольку во время компиляции определить, какие единицы номера могут использоваться, когда требуется новый, во время выполнения, далеко не тривиально, я полагаю, вам придется отказаться от старомодного подхода к выбору нового подразделения номера из заранее определенного диапазона, который вы знаете (или, если код достаточно большой и сложный, просто надежда) еще не используется.