LambdaBeta
LambdaBeta

Reputation: 1505

gprbuild get external information into source

I am trying to have gprbuild automatically set some variables' values in my source code - one way or another. In particular I want the outputs of certain commands to be accessible from within the code. In C with Makefiles this is easy:

source:

#include <stdio.h>
int main() { printf("%s\n", COMMAND_OUTPUT); return 0; }

make:

result : source.c
    $(CC) -DCOMMAND_OUTPUT=`command -with -options`

However I have no idea how to do such a thing with gprbuild and Ada. (Short of ditching gprbuild and just using make - but I rather like gprbuild)

Upvotes: 1

Views: 588

Answers (3)

TamaMcGlinn
TamaMcGlinn

Reputation: 3248

Yes, the gnatprep preprocessor allows exactly the same as what you have in your C code:

main.adb:

with Ada.Text_IO; use Ada.Text_IO;

procedure Main is
begin
   Put_Line ($Command_Output);
end Main;

simple_gnatprep.gpr:

project simple_gnatprep is

   for Create_Missing_Dirs use "True";

   Command_Output := external ("Command_Output");

   for Source_Dirs use (".");
   for Exec_Dir use ".";
   for Main use ("main.adb");

   for Object_Dir use "obj/" & "CommandOutput_" & Command_Output;

   package Compiler is
      for Switches ("Ada") use ("-gnateDCommand_Output=""" & Command_Output & """");
   end Compiler;
end simple_gnatprep;

Makefile:

COMMAND_OUTPUT=$(shell echo hello there)

all:
    gprbuild -d -p -g -XCommand_Output='${COMMAND_OUTPUT}'

clean:
    rm -rf obj/ *.exe

Note I have included the command output in the obj/ directory used, which will fail if the command outputs any symbol that cannot appear in a directory name. However, if you omit it then gprbuild will say that your executable is up-to-date when nothing has changed except the output of the command.

Another option is to always remove the object directory before compiling, but when possible it is better to include the value of any preprocessor symbols in the object path so that switching from one configuration (e.g. Debug / Release) to another and back doesn't throw away intermediate results and slow down your development process.

Gnatprep is only included in the GNAT compiler, because there isn't yet any provision for preprocessing in the Ada standard. For other compilers, you will need to run each file through gnatprep separately in the Makefile, and then pass it to the compiler. In this case there is no need to fiddle with object directory names, as the source file will always be new and the compiler will always have to recompile everything.

Upvotes: 1

Jacob Sparre Andersen
Jacob Sparre Andersen

Reputation: 6611

I solve that by generating an Ada file from the makefile before building.

An example:

HG_STATE_SOURCE     = src/mercurial.ads
HG_MODIFIER         = `test $$(hg status | wc -c || echo 0) -gt 0 && echo "plus changes" || echo "as committed"`
HG_REVISION         = `hg tip --template '{node}' 2>/dev/null || echo N/A_____________________________________`

[...]

$(HG_STATE_SOURCE): Makefile $(REPOSITORY_CONFIG) $(REPOSITORY_STATE) $(PROJECT_ROOT_SOURCE)
    @mkdir -p src
    @echo 'package 'Mercurial is'                                >  $(HG_STATE_SOURCE)
    @echo '   Revision : constant String (1 .. 53) :='           >> $(HG_STATE_SOURCE)
    @echo '                "'$(HG_REVISION)' '$(HG_MODIFIER)'";' >> $(HG_STATE_SOURCE)
    @echo 'end 'Mercurial;'                                      >> $(HG_STATE_SOURCE)

Upvotes: 2

Jim Rogers
Jim Rogers

Reputation: 5051

Ada does not use a preprocessor like C does.You cannot expect Ada compilers to modify strings in your code. Use of such inline editing can easily become a violation of Ada strong typing, which would be very difficult to diagnose and would be completely invisible to source code static analysis.

Upvotes: 2

Related Questions