У меня необычная ситуация, при которой код уточнения просто не выполняется вообще. Это не вопрос порядка разработки, а скорее вопрос разработки вообще.
Проблема в том, что я вообще не «с» рассматриваемой единицей, хотя теоретически она должна быть доступна, пока происходит ее разработка.
Конечно, я мог бы просто добавить бесполезное «с» для рассматриваемой единицы, но в моем реальном случае использования есть большое количество единиц, с которыми мне пришлось бы это делать.
Мой вопрос заключается в том, есть ли какой-либо способ в коде, с помощью прагм, в файле проекта gpr или с помощью переключателей командной строки, чтобы я мог заставить компилятор включить файл, даже если он думает, что файл не указан?
Вот минимальный рабочий пример:
как.объявления:
package As is
type A is tagged null record;
type Nothing is null record;
function Create (Ignored : not null access Nothing) return A;
function Image (From : A) return String;
end As;
как.adb:
package body As is
function Create (Ignored : not null access Nothing) return A is
(null record);
function Image (From : A) return String is ("A");
end As;
поиск.объявления:
with Ada.Tags;
package Finder is
procedure Register (Name : String; Tag : Ada.Tags.Tag);
function Find (Name : String; Default : Ada.Tags.Tag) return Ada.Tags.Tag;
end Finder;
Finder.adb:
with Ada.Containers.Indefinite_Vectors;
package body Finder is
type Name_Tag (Size : Natural) is
record
Name : String (1 .. Size);
To : Ada.Tags.Tag;
end record;
package Name_Tag_Vectors is new Ada.Containers.Indefinite_Vectors (Positive, Name_Tag);
Name_Tags : Name_Tag_Vectors.Vector := Name_Tag_Vectors.Empty_Vector;
procedure Register (Name : String; Tag : Ada.Tags.Tag) is begin
Name_Tags.Append ((Name'Length, Name, Tag));
end Register;
function Find (Name : String; Default : Ada.Tags.Tag) return Ada.Tags.Tag is begin
for Tag of Name_Tags loop
if Tag.Name = Name then
return Tag.To;
end if;
end loop;
return Default;
end Find;
end Finder;
bs.объявления:
with As;
package Bs is
type B is new As.A with null record;
function Create (Ignored : not null access As.Nothing) return B;
function Image (From : B) return String;
end Bs;
бс.адб:
with Finder;
package body Bs is
function Create (Ignored : not null access As.Nothing) return B is
(As.Create (Ignored) with null record);
function Image (From : B) return String is ("B");
begin
Finder.Register ("B", B'Tag);
end Bs;
тест.adb:
with As; use As;
-- with Bs; -- (uncommenting this line solves my problem, but what if I had the rest of the alphabet?)
with Finder;
with Ada.Tags.Generic_Dispatching_Constructor;
with Ada.Text_IO;
procedure Test is
function Constructor is new Ada.Tags.Generic_Dispatching_Constructor (
T => A,
Parameters => Nothing,
Constructor => Create);
Nada : aliased Nothing := (null record);
What : A'Class := Constructor (Finder.Find ("B", A'Tag), Nada'Access);
begin
Ada.Text_IO.Put_Line (What.Image);
end Test;





Компилятор считает, что на ваш пакет Bs нет ссылок, потому что это не так. У вас нет для него пункта with, поэтому он не является частью вашей программы.
Простой пример:
а.объявления
package A is
procedure Blah;
end A;
а.adb
with Ada.Text_IO;
package body A is
procedure Blah is begin null; end Blah;
begin
Ada.Text_IO.Put_Line("Elaborate A");
end A;
б.объявления
package B is
procedure Blah;
end B;
б.адб
with Ada.Text_IO;
package body B is
procedure Blah is begin null; end Blah;
begin
Ada.Text_IO.Put_Line("Elaborate B");
end B;
main.adb
with Ada.Text_IO;
with A;
procedure Main is
begin
Ada.Text_IO.Put_Line("Main");
end Main;
Когда я запускаю main, он печатает
Elaborate A
Main
Он не печатает Elaborate B, потому что этот пакет не является частью программы; это просто пара исходных файлов в одном каталоге.
Очевидное решение — добавить пункты with.
Я не знаю, есть ли менее очевидное решение. Если есть, это, вероятно, зависит от компилятора. Но я не уверен, зачем компилятору иметь функцию, позволяющую включать в программу неиспользуемый пакет.
другого решения нет. Создание библиотеки не помогает. Создание инкапсулированной библиотеки также не работает, потому что вы должны указать bs в интерфейсах, чтобы она была разработана.
Что я сделал (например, здесь ff), так это фактически сослался на единицы измерения в основной программе (с pragma Unreferenced для предотвращения предупреждений).
В качестве альтернативы вы можете иметь пакет, например. Required_Units со всеми необходимыми with включенными, а затем with из основной программы.
Даже если бы был какой-то альтернативный процесс, вы должны были бы сказать ему, какие единицы вам нужно включить; можно также плыть по течению и сделать это на Аде!
Я собираюсь пойти с этим решением. Добавлю в процесс сборки скрипт, который ищет нужные юниты и генерирует такой пакет.
Интересно, поможет ли создание проекта библиотеки и объявление всего необходимого пакета в качестве интерфейса, а затем использовать проект библиотеки в реальном исполняемом файле? наличие их в интерфейсе заставит символы существовать?
@LoneWanderer, ну, я думаю, это будет зависеть от типа проекта. Если бы это были просто статические помехи, вероятно, нет; если отдельно, то возможно.
Поскольку пакет Bs невидим для вашей программы, то и тип B невидим.
Так что следующий вопрос: зачем нужно регистрировать тип B, если он нигде не используется?
Если бы компилятор Ады разработал все модули (пакеты или автономные подпрограммы), которые не имеют отношения к основной программе, но видны через исходный путь, это стало бы действительно грязным!...
выглядит как автоматическая регистрация объектов. Не уверен, что это можно сделать на Аде (легко на С++ с
staticтрюками)