Pregunta

I am working in a FORTRAN code project where compilation decisions are taken in two files: a header file (definitions.h), which is included from the relevant FORTRAN files, and the makefile. For example, the compiler, some sets of libraries, and the sort of parallelization allowed (MPI, OpenMP, or none) are chosen in the makefile, and the inclusion of some parts of the code is controled by #define directives in the header.

  1. I don't like having to edit two different files to setup the compilation. Is there a better approach?

  2. Besides, both the makefile and the definitions.h files are under revision control. This means that my fellow careless developers commit and push new versions of both files where they have only changed the compilation options enabled, therefore polluting the revision control history. Ideally, at least the largest file (the makefile) would not have to be edited to set the compilation options.

  3. In some cases, inconsistencies happen. Typically, some combinations of libraries chosen in the makefile are incompatible with some sections of code selected by the #define directives. Is there any way to check this properly?

    E.g., in order to stop compilation if LIB1=LIBFOO (in the makefile) and bar is defined to 1 (in the headers file), I was trying the following bit of code in the makefile

    ifeq ($(LIB1), LIBFOO)
        bar_status:=`grep -i '^[[:space:]]*\#define[[:space:]]*bar[[:space:]]*[[:digit:]]' definitions.h | tail -n1 | grep -ic '^[[:space:]]*#define[[:space:]]*bar[[:space:]]*1[[:space:]]*'`
    ifeq ($(bar_status), 1)
        $(error ERROR: You are trying to compile the code with bar enabled in definitions.h, but this is incompatible with the library LIBFOO selected in the makefile)
    endif
    endif
    

    but (a) this is extremely ugly, and (b) apparently it is not working at all. How can this be fixed?


I worked on 3., and I think I sort of have an answer for it: I add a new .PHONY target, ini_check, which is a requisite for the other relevant targets, and reads

ifeq ($(LIB1), LIBFOO)
    bar_value:=$(shell echo bar | cat definitions.h - | gcc -E -undef - 2>/dev/null | tail -n1)
endif

ini_check:
ifeq ($(LIB1), LIBFOO)
ifeq ($(bar_value), 1)
    $(error ERROR: You are trying to compile the code with bar enabled in definitions.h, but this is incompatible with the library LIBFOO selected in the makefile)
endif
endif
    @echo "Done with the initial check, starting compilation..."

Note that now I use the C preprocessor to get the value of the variable bar after parsing the header.

¿Fue útil?

Solución

If it's your policy to run Make without flags or arguments, you can still save yourself some grief by putting the relevant switches in an adjunct file (not under version control) which the makefile will include.

Parsing source files with Make as you've tried to do is, as you say, both ugly and difficult. And it's a nightmare to maintain. I recommend keeping two versions of definitions.h under version control in different directories; the same same Make logic that chooses libraries can choose the header file.

I don't know what kind of errors you're getting when your header file is "incompatible" with the libraries, but if the libraries have different interfaces, you may be able to deliberately invoke compiler errors by putting some library-specific calls in the header files. (And if they don't have different interfaces, you seem to have some bad implementation-dependent behavior.)

Finally, if "a few minutes" is too long to wait for such a compiler error, then you must be making such errors pretty often-- you might want to look into your procedures. (Also, if you've modified only one or two files, a build shouldn't take that long-- a daily build, yes, but not the kind you do several times an hour.)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top