有没有办法指示Ada编译器选择代码块?

时间:2017-01-23 10:48:10

标签: ada

我想指示Ada编译器在两个不同的代码块之间进行选择,具体取决于预定义的静态编译器指令,例如“DEBUG”或“RELEASE”。我想做这样的事情:

如果DEBUG那么  <编译本代码> 结束如果;

如果RELEASE那么  <编译本其他代码> 结束如果;

C#和其他语言为此提供#define指令。 Ada有类似的东西吗?如果没有,这在Ada中是如何完成的?

3 个答案:

答案 0 :(得分:8)

良好的Ada风格是完全按照您的方式编写,确保实体DebugRelease是静态的。

这样做的一种方法是拥有一个包,比如Compilation_Mode,它有两种变体:

package Compilation_Mode is
   Debug   : constant Boolean := False;
   Release : constant Boolean := True;
end Compilation_Mode;

package Compilation_Mode is
   Debug   : constant Boolean := True;
   Release : constant Boolean := False;
end Compilation_Mode;

然后让您的构建系统选择适当的包。 (使用gprbuild,您可以在项目文件中使用package Naming。)

答案 1 :(得分:4)

这不是很简单,但可能的方法是使用单独的编译单元。例如,假设您位于名为Pkg的包的主体内部,并且希望某些代码根据某些方案变量执行不同的操作(这是一个GNAT GPRBuild术语,但是该方法也可以与其他构建系统一起使用)。您将该代码移动到某个子例程中,让我们说Do_Something,并将其声明为separate

package body Pkg is 
   -- ...
   procedure Do_Something is separate;
   -- ...
end Pkg;

这告诉编译器此过程被定义为单独的编译单元。现在,您将两个(或任意数量)的实现放在两个单独的文件中,如下所示:

separate (Pkg) procedure Do_Something is
   -- ...
begin
   -- ...
end Do_Something;

这告诉编译器这是Pkg内单独编译单元的定义。是的,这意味着对于每一堆代码,您需要编写两个(或 n n =不同实现的数量)附加文件。

管理这些文件的一个好方法是将所有 debug 实现放在 debug 目录中,同样用于 release 实现。然后,您指示构建系统从一个或另一个目录加载源。例如,使用GPRBuild:

project My_Project is
   -- define legal modes
   type Mode_Type is ("debug", "release");

   -- load mode from environment variable `Mode`, defaulting to "debug"
   Mode : Mode_Type = external ("Mode", "debug");

   -- add directory with appropriate separate implementations
   case Mode is
   when "debug" =>   My_Sources := My_Sources & "src/debug";
   when "release" => My_Sources := My_Sources & "src/release";
   end case;

   -- define where the compiler should load sources from
   for Source_Dirs use My_Sources;

   -- ...
end My_Project;

你的src文件夹会有这样的布局:

src
   debug
      pkg-do_something.adb
   release
      pkg-do_something.adb
   pkg.adb
   pkg.ads

此方法适用于多个正交方案值。它还会强制您将特定于场景的代码与通用代码分开,这可能被认为是好事,但是ymmv。

答案 2 :(得分:2)

Ada没有,但最受欢迎的Ada工具集(GNAT)包含一个工具 gnatprep (请参阅here)来执行此操作。其他工具集可能包括等价物。

例如,

  RCC.RCC_Periph.AHB1ENR           := ($SCL_Enable => 1, others => <>);
  $SCL_GPIO.MODER.Arr ($SCL_Pin)     := 2; -- alternate function
  $SCL_GPIO.OTYPER.OT.Arr ($SCL_Pin) := 1; -- open drain
  $SCL_GPIO.OSPEEDR.Arr ($SCL_Pin)   := 1; -- medium speed
  $SCL_GPIO.PUPDR.Arr ($SCL_Pin)     := 0; -- nopullup, no pulldown
  #if SCL_Pin < 8 then
  $SCL_GPIO.AFRL.Arr ($SCL_Pin)   := 4; -- DocID022152 Rev 6 Table 9
  #else
  $SCL_GPIO.AFRH.Arr ($SCL_Pin)   := 4; -- DocID022152 Rev 6 Table 9
  #end if;

如果使用此Makefile片段进行翻译

src/i2c1-device.adb: ../i2c/src/i2c-device.adb.pp $(DEFINITION)
    gnatprep                \
      -c -v                 \
      $<                    \
      $@                    \
      $(DEFINITION)

文件$(DEFINITION)包含

SCL_Enable := GPIOBEN
SCL_GPIO   := GPIO.GPIOB_Periph
SCL_Pin    := 8

结果

      RCC.RCC_Periph.AHB1ENR           := (GPIOBEN => 1, others => <>);
      GPIO.GPIOB_Periph.MODER.Arr (8)     := 2; -- alternate function
      GPIO.GPIOB_Periph.OTYPER.OT.Arr (8) := 1; -- open drain
      GPIO.GPIOB_Periph.OSPEEDR.Arr (8)   := 1; -- medium speed
      GPIO.GPIOB_Periph.PUPDR.Arr (8)     := 0; -- nopullup, no pulldown
--!       #if SCL_Pin < 8 then
--!       $SCL_GPIO.AFRL.Arr ($SCL_Pin)   := 4; -- DocID022152 Rev 6 Table 9
--!       #else
      GPIO.GPIOB_Periph.AFRH.Arr (8)   := 4; -- DocID022152 Rev 6 Table 9
--!       #end if;