How to make GPR accept multiple sources in the same project having the same file name? - ada

I set out to rewrite an OSS project in C piece by piece to Ada. First stop being to replace the build system with GPR. On doing so I stumbled upon a problem: it does not allow for multiple sources in the repository with the same name:
duplicate source file name "slp_debug.h"
The file exists in two different directories; one for implementation, and one for test (stub I reckon). This should be just fine since the preprocessor will deterministically choose the source relative the source including it, or according to the order of include directories. But GPR would appear not fond of that idea.
How to make GPR accept it?

I had a go with openslp-2.0.0 and managed to make one GPR that builds the library and another, which withs the first, to build the tests - no complaints about the duplicate file.
Both project files are at the top level.
As common for projects like openslp, the configure process generates a lengthy config.h, at the top level, with a shedload of #define HAVE_FOO 1’s.
This is the 'common' project file - I think there may also be an executable in there (slptool), which might have to be a separate GPR since this one builds a library:
project Openslp is
for Languages use ("c");
for Source_Dirs use ("common", "libslp", "libslpattr");
for Excluded_Source_Files use
(
"slp_win32.c", -- not on Darwin! or Linux, ofc
"libslpattr_tiny.c" -- I think this must be an alternate version
);
for Library_Name use "slp";
for Library_Kind use "static";
for Library_Dir use "lib";
for Object_Dir use "obj-openslp";
for Create_Missing_Dirs use "true";
package Compiler is
for Switches ("c") use
(
"-DDARWIN",
"-DHAVE_CONFIG_H",
"-I" & project'Project_Dir, -- for config.h, created by configure
"-I" & project'Project_Dir & "/common",
"-I" & project'Project_Dir & "/libslp",
"-I" & project'Project_Dir & "/libslpattr",
"-DETCDIR=""" & project'Project_Dir & "/etc"""
);
end Compiler;
end Openslp;
and this is the 'test' one:
with "openslp";
project Openslp_Test is
for Languages use ("c");
for Source_Dirs use ("test/**");
for Object_Dir use "obj-openslp_test";
for Exec_Dir use "test/bin";
for Main use ("SLPFindAttrs.c"); -- etc, etc
for Create_Missing_Dirs use "true";
package Compiler is
for Switches ("c") use
("-I" & project'Project_Dir & "/test") -- for the local slp_debug.h
& Openslp.Compiler'Switches ("c");
end Compiler;
end Openslp_Test;

Related

Premake5 android makefile declare prebuilt library

Using premake5 file to generate make files for android. I am trying to produce the prebuilt library declaration as described in https://developer.android.com/ndk/guides/prebuilts.html
More precisely
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := foo-prebuilt
LOCAL_SRC_FILES := libfoo.so
include $(PREBUILT_SHARED_LIBRARY)
What kind of project would introduce the include include $(PREBUILT_SHARED_LIBRARY) or what other option do I need to include?
I have little knowledge in this, but I was able to use android PREBUILT_SHARED_LIBRARY - in premake4 using the following lua script:
The script is customised for the example you've give above.
linklibs = {"foo"}
libdirpaths = {"../../path/to/libs/"}
project "project_using_foo"
language "C"
kind "SharedLib"
files (android.srcfiles)
includedirs (includepaths)
location "build"
links (linklibs)
libdirs (libdirpaths)
buildoptions (buildoptions)
androidappabi {"armeabi-v7a"}
androidsdk "android-19"
where libfoo.so will be in ../../path/to/libs/$(TARGET_ARCH_ABI)/libfoo.so
[$(TARGET_ARCH_ABI) in this case is "armeabi-v7a"]

Overriding adb package body from a with-ed .gpr project

I'm using GNAT gprbuild.
I have a project file, A.gpr that withs project file B.gpr .
There is the possibility that the B.gpr project file could be a few with-ed levels deep from A.gpr
B.gpr has source files X.adb and X.ads .
A.gpr defines a main file Y.adb that withs X.ads
Its a requirement that A.gpr must with B.gpr.
By only extending or editing A.gpr I would like to use a different X.adb .
How do i do this?
The closest thing I have found so far is https://gcc.gnu.org/onlinedocs/gnat_ugn/Project-Extension.html.
However I keep hitting the error:
unit "X" cannot belong to several projects
project "A" {overriding X.adb file path}
unit "X" already belongs to project "B"
project "B" {original x.adb filepath}
If files (in this case different x.adb) are in different directories it is possible by use of case statement.
For example in some of my gpr files I have following lines:
type OS_Type is ("Unix", "Windows");
OS: OS_Type := external ("OS", "Unix");
case OS is
when "Unix" =>
for Source_Dirs use ("src", "src/unix");
when "Windows" =>
for Source_Dirs use ("src", "src/windows");
end case;
As you can see, depending on variable different source directories are used.
(OS defaults to "Unix", to set variable you add
-Xvariable=value to you gprbuild call [which in this example would be
-XOS=Windows]).
Here's an example that uses both paths and body-selection based on project variables:
project Example is
for Object_Dir use "obj";
for Exec_Dir use ".";
type Language_Type is
("Spanish", "English");
Language : Language_Type := external ("Language", "English");
for Source_Dirs use ("src", "src/" & Language);
for Main use ("testbed.adb");
type Starts_Week_Type is
("mon", "tue", "wed", "thu", "fri", "sat", "sun");
Starts_Week : Starts_Week_Type := external ("Starts_Week", "sun");
package Ide is
for Documentation_Dir use "doc";
end Ide;
package Prove is
for Switches use ("-j4");
end Prove;
package Builder is
for Default_Switches ("ada") use ("-j4", "-C", "-g");
end Builder;
package Compiler is
for Default_Switches ("ada") use
("-gnato", "-fstack-check", "-gnatE", "-gnata", "-gnat12", "-g", "-gnatf");
end Compiler;
package Binder is
for Default_Switches ("ada") use ("-shared");
end Binder;
package Linker is
for Default_Switches ("ada") use ("-g");
end Linker;
package Naming is
for Specification("Example.Types.Week") use
"Example-types-"&Starts_Week&"_week.ada";
end Naming;
end Example;
As you can see the line for Source_Dirs use ("src", "src/" & Language); makes the src and either src/English or src/Spanish the directories that will be searched/used when looking for source files.
Later, in Naming, we have a file whose name is dependent on a project variable being selected as the body of the indicated file. -- Namely the file types-XXX_week.ada where XXX is one of the three-letter day-abbreviations the Starts_Week scenario-variable may take.

ADA File Names vs. Package Names

I inherited an ADA program where the source file names and package file names don't follow the default naming convention. ADA is new to me, so I may be missing something simple, but I can't see it in the GNAT Pro User's Guide. (This similar question didn't help me.)
Here are a couple of examples:
File Name: C_Comm_Config_S.Ada
Package Name: Comm_Configuration
File Name: D_Bus_Buffers_S.Ada
Package Name: Bus_Buffers
I think I have the _S.Ada and _B.Ada sorted out, but I can't find anything in the program source or build files that show the binding between the Package Name and the rest of the File Name.
When I compile a file that doesn't use any other packages, I get a warning: file name does not match unit name... This appears to be from the prefix of C_ or D_, in this particular case.
Also, I'm not clear if the prefixes C_ and D_ have any special meaning in the context of ADA, but if it does, I'd like to know about it.
So I appear to have two issues, the Prefix of C_ or D_ and in some cases the rest of the file name doesn't match the package.
You could use gnatname: see the User’s Guide.
I copied subdirectories a/ and d/ from the ACATS test suite to a working directory and created a project file p.gpr:
project p is
for source_dirs use ("a", "d");
end p;
and ran gnatname with
gnatname -P p -d a -d d \*.ada
which resulted in an edited p.gpr and two new files, p_naming.gpr and p_source_list.txt. These are rather long, but look like
p.gpr:
with "p_naming.gpr";
project P is
for Source_List_File use "p_source_list.txt";
for Source_Dirs use ("a", "d");
package Naming renames P_Naming.Naming;
end P;
p_naming.gpr:
project P_Naming is
for Source_Files use ();
package Naming is
for Body ("d4a004b") use "d4a004b.ada";
for Body ("d4a004a") use "d4a004a.ada";
for Body ("d4a002b") use "d4a002b.ada";
...
for Body ("aa2010a_parent.boolean") use "aa2010a.ada" at 4;
for Body ("aa2010a_parent") use "aa2010a.ada" at 3;
for Spec ("aa2010a_parent") use "aa2010a.ada" at 2;
for Spec ("aa2010a_typedef") use "aa2010a.ada" at 1;
...
for Body ("a22006d") use "a22006d.ada";
for Body ("a22006c") use "a22006c.ada";
for Body ("a22006b") use "a22006b.ada”;
end Naming;
end P_Naming;
The for Body ("aa2010a_parent") use "aa2010a.ada" at 3; is used when there’s more than one unit in the source file.
p_source_list.txt:
a22006b.ada
a22006c.ada
a22006d.ada
a27003a.ada
a29003a.ada
...
d4a002b.ada
d4a004a.ada
d4a004b.ada
When building, for example, test d4a004b, you have to use the file name and suffix:
gnatmake -P p d4a004b.ada
The Ada standard does not say anything about source file naming conventions. As it appears that you use GNAT, I assume that you mean the "GNAT default naming convention".
You can tell GNAT about alternatively named files in a Naming package inside your project files.
A simple example:
project OpenID is
...
package Naming is
for Implementation ("Util.Log.Loggers.Traceback")
use "util-log-loggers-traceback-gnat.adb";
for Implementation ("Util.Serialize.IO.XML.Get_Location")
use "util-serialize-io-xml-get_location-xmlada-4.adb";
end Naming;
end OpenID;

how to compile MPI and non-MPI version of the same program with automake?

I have a C++ code that can be compiled with MPI support depending on a
certain preprocessor flag; missing the appropriate flag, the sources
compile to a non-parallel version.
I would like to setup the Makefile.am so that it compiles both the
MPI-parallel and the sequential version, if an option to
./configure is given.
Here's the catch: MPI has its own C++ compiler wrapper, and insists
that sources are compiled and linked using it rather than the standard
C++ compiler. If I were to write the Makefile myself, I would have to
do something like this:
myprog.seq: myprog.cxx
$(CXX) ... myprog.cxx
myprog.mpi: myprog.cxx
$(MPICXX) -DWITH_MPI ... myprog.cxx
Is there a way to tell automake that it has to use $(MPICXX) instead
of $(CXX) when compiling the MPI-enabled version of the program?
I have the same problem, and I've found that there's no really good way to get autotools to conditionally use MPI compilers for particular targets. Autotools is good at figuring out which compiler to use based on what language your source is written in (CC, CXX, FC, F77, etc.), but it really isn't good at figuring out whether or not to use MPI compiler for a particular target. You can set MPICC, MPICXX, etc., but you essentially have to rewrite all your Makefile rules for your target (as you've done above) if you use the compiler this way. If you do that, what's the point of writing an automake file?
Someone else suggested using MPI like an external library, and this is the approach I'd advocate, but you shouldn't do it by hand, because different MPI installations have different sets of flags they pass to the compiler, and they can depend on the language you're compiling.
The good thing is that all the currently shipping MPI compilers that I know of support introspection arguments, like -show, -show-compile or -show-link. You can automatically extract the arguments from the scripts.
So, what I did to deal with this was to make an m4 script that extracts the defines, includes, library paths, libs, and linker flags from the MPI compilers, then assigns them to variables you can use in your Makefile.am. Here's the script:
lx_find_mpi.m4
This makes MPI work the way automake expects it to. Incidentally, this is the approach CMake uses in their FindMPI module, and I find it works quite well there. It makes the build much more convenient because you can just do something like this for your targets:
bin_PROGRAMS = mpi_exe seq_exe
# This is all you need for a sequential program
seq_exe_SOURCES = seq_exe.C
# For an MPI program you need special LDFLAGS and INCLUDES
mpi_exe_SOURCES = mpi_exe.C
mpi_exe_LDFLAGS = $(MPI_CXXLDFLAGS)
INCLUDES = $(MPI_CXXFLAGS)
There are similar flags for the other languages since, like I said, the particular flags and libraries can vary depending on which language's MPI compiler you use.
lx_find_mpi.m4 also sets some shell variables so that you can test in your configure.ac file whether MPI was found. e.g., if you are looking for MPI C++ support, you can test $have_CXX_mpi to see if the macro found it.
I've tested this macro with mvapich and OpenMPI, as well as the custom MPICH2 implementation on BlueGene machines (though it does not address all the cross-compiling issues you'll see there). Let me know if something doesn't work. I'd like to keep the macro as robust as possible.
I am sorry that having automake use MPI is so difficult. I have been struggling with this for many months trying to find a good solution. I have a source tree that have one library and then many programs in sub-folders that use the library. Some of the folders are mpi programs, but when I try to replace CXX with the MPI compiler using in Makefile.am.
if USE_MPI
MPIDIR = $(MPICOMPILE)
MPILIB = $(MPILINK)
CXX=#MPICXX#
F77=#MPIF77#
MPILIBS=$(MPILINK)
endif
I get
CXX was already defined in condition TRUE, which includes condition USE_MPI ...
configure.ac:12: ... `CXX' previously defined here
I don't have a rule that specifies the compiler, so maybe there is a way to do that.
SUBDIRS = .
bin_PROGRAMS = check.cmr
check_ccmr_SOURCES = check_gen.cpp
check_ccmr_CXXFLAGS = -I$(INCLUDEDIR) $(MPIDIR)
check_ccmr_LDADD = -L$(LIBDIR)
check_ccmr_LDFLAGS = $(MPILIB)
If you have disabled the subdir-objects option to automake, something like this might work:
configure.ac:
AC_ARG_ENABLE([seq], ...)
AC_ARG_ENABLE([mpi], ...)
AM_CONDITIONAL([ENABLE_SEQ], [test $enable_seq = yes])
AM_CONDITIONAL([ENABLE_MPI], [test $enable_mpi = yes])
AC_CONFIG_FILES([Makefile seq/Makefile mpi/Makefile])
Makefile.am:
SUBDIRS =
if ENABLE_SEQ
SUBDIRS += seq
endif
if ENABLE_MPI
SUBDIRS += mpi
endif
sources.am:
ALL_SOURCES = src/foo.c src/bar.cc src/baz.cpp
seq/Makefile.am:
include $(top_srcdir)/sources.am
bin_PROGRAMS = seq
seq_SOURCES = $(ALL_SOURCES)
mpi/Makefile.am:
include $(top_srcdir)/sources.am
CXX = $(MPICXX)
AM_CPPFLAGS = -DWITH_MPI
bin_PROGRAMS = mpi
mpi_SOURCES = $(ALL_SOURCES)
The only thing stopping you from doing both of these in the same directory is the override of $(CXX). You could, for instance, set mpi_CPPFLAGS and automake would handle that gracefully, but the compiler switch makes it a no-go here.
A possible workaround for not using different sources could be:
myprog.seq: myprog.cxx
$(CXX) ... myprog.cxx
myprog-mpi.cxx: myprog.cxx
#cp myprog.cxx myprog-mpi.cxx
myprog.mpi: myprog-mpi.cxx
$(MPICXX) -DWITH_MPI ... myprog-mpi.cxx
#rm -f myprog-mpi.cxx
for Automake:
myprog-bin_PROGRAMS = myprog-seq myprog-mpi
myprog_seq_SOURCES = myprog.c
myprog-mpi.c: myprog.c
#cp myprog.c myprog-mpi.c
myprog_mpi_SOURCES = myprog-mpi.c
myprog_mpi_LDFLAGS = $(MPI_CXXLDFLAGS)
INCLUDES = $(MPI_CXXFLAGS)
BUILT_SOURCES = myprog-mpi.c
CLEANFILES = myprog-mpi.c
Here is the solution that I came up with for building a two static libraries - one with MPI (libmylib_mpi.a) and one without (libmylib.a). The advantage of this method is that there is no need for duplicate source files, a single Makefile.am for both variants, and capability to use subdirs. You should be able to modify this as needed to produce a binary instead of a library. I build the non-MPI library as normal, then for the MPI variant, I leave _SOURCES empty and use _LIBADD instead, specifying an extension of .mpi.o for the object files. I then specify a rule to generate the MPI object files using the MPI compiler.
Overall file / directory structure is something like
configure.ac
Makefile.am
src
mylib1.cpp
mylib2.cpp
...
include
mylib.h
...
configure.ac:
AC_INIT()
AC_PROG_RANLIB
AC_LANG(C++)
AC_PROG_CXX
# test for MPI, define MPICXX, etc. variables, and define HAVE_MPI as a condition that will evaluate to true if MPI is available and false otherwise.
AX_MPI([AM_CONDITIONAL([HAVE_MPI], [test "1" = "1"])],[AM_CONDITIONAL([HAVE_MPI], [test "1" = "2"])]) #MPI optional for xio
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
There is probably a more efficient way to do the conditional check than I have listed here (I'm welcome to suggestions).
Makefile.am:
AUTOMAKE_OPTIONS = subdir-objects
lib_LIBRARIES = libmylib.a
libmylib_a_SOURCES = src/mylib_1.cpp src/mylib_2.cpp ...
#conditionally generate libmylib_mpi.a if MPI is available
if HAVE_MPI
lib_LIBRARIES += libmylib_mpi.a
libmylib_mpi_a_SOURCES = #no sources listed here
#use LIBADD to specify objects to add - use the basic filename with a .mpi.o extension
libmylib_mpi_a_LIBADD = src/mylib_1.mpi.o src/mylib_2.mpi.o ...
endif
AM_CPPFLAGS = -I${srcdir}/include
include_HEADERS = include/mylib.h
# define a rule to compile the .mpi.o objects from the .cpp files with the same name
src/%.mpi.o: ${srcdir}/src/%.cpp ${srcdir}/include/mylib.h
$(MPICXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -DWITH_MPI=1 -c $(patsubst %.mpi.o,$(srcdir)/%.cpp,$#) -o $#
#define a rule to clean the .mpi.o files
clean-local:
-rm -f src/*.mpi.o
MPI installations do (usually) ship with compiler wrappers, but there is no requirement that you use them -- MPI does not insist on it. If you want to go your own way you can write your own makefile to ensure that the C++ compiler gets the right libraries (etc). To figure out what the right libraries (etc) are, inspect the compiler wrapper which is, on all the systems I've used, a shell script.
At first sight the compiler wrappers which ship with products such as the Intel compilers are a little daunting but stop and think about what is going on -- you are simply compiling a program which makes use of an external library or two. Writing a makefile to use the MPI libraries is no more difficult than writing a makefile to use any other library.

Error in Ada separate file

I am translating a Ada83 to Ada95 file. The problem happens when I try to compile a file which calls a separate. The error is "Illegal character " and refers to directive to preprocessor:
with BAS_PUT;
#if ADA_COMPILER="GNAT" then
WITH ADA.GNAT_PUT;
#else
WITH ADA_PUT;
#end if;
separate(A_CALL_PUT)
procedure ....
This problem does not happen when the same preprocessor directive is in a file adb that it is not a separate function.
Someone can help me???
Ada has no preprocessor, so # is indeed an illegal character.
Some compilers (eg: Gnat) do come with one, but if so it is one of their own devising. If you like you can set up your build system to run your Ada source files through external preprocessor (eg: the C pre-processor). I've never done that, but I'm told its eminently doable.
If your compiler does happen to come with a preprocessor, it is non-standard. Use it if you like, but by definition it will be useless for creating portable source files (which appears to be what you are trying to do with it).
Most folks would consider it better form to just create different source files for your different environments, and have the build environment (make rules?) switch between them.

Resources