Ada: Gnat generates bad .o file - ada

My code is:
with Ada.Text_IO; use Ada.Text_IO;
procedure Hello is
begin
Put_Line ("Hello, world!");
end Hello;
GNAT makes a .o and .ali.
I type
gcc hello.o -o hello
GCC complains:
/usr/lib/gcc/i686-linux-gnu/6/../../../i386-linux-gnu/crt1.o: In function `_start':
(.text+0x18): undefined reference to `main'
hello.o: In function `_ada_hello':
hello.adb:(.text+0x26): undefined reference to `ada__text_io__put_line__2'
collect2: error: ld returned 1 exit status

You shouldn't try to compile Ada programs by hand with the gcc command. There are two sensible alternatives depending on your preferences:
Use the gnatmake command as Brian suggests in his comment. This works well as long as all the relevant source files are stored in the same directory.
Create a project file and use gprbuild. Projects can handle source files distributed in multiple directories, include other projects, contain compiler and linker flags, etc.
On the "Hello_World" level, gnatmake works okay, but you should be aware that gnatmake doesn't behave like a real Ada compiler, unless you pass it some specific flags. I've managed this with an alias in my shell, but in reality it is yet another argument in favour of using gprbuild even for tiny projects, as you can put the flags which make GCC behave like a real Ada compiler in the project files, and not worry more about it.
project Hello_World is
for Source_Dirs use ("src");
for Object_Dir use "obj";
for Exec_Dir use "bin";
for Main use ("hello.adb");
package Builder is
for Default_Switches ("Ada")
use ("-m");
end Builder;
package Compiler is
for Default_Switches ("Ada")
use ("-fstack-check", -- Generate stack checking code (part of Ada)
"-gnata", -- Enable assertions (part of Ada)
"-gnato13", -- Overflow checking (part of Ada)
"-gnatf", -- Full, verbose error messages
"-gnatwa", -- All optional warnings
"-gnatVa", -- All validity checks
"-gnaty3abcdefhiklmnoOprstux", -- Style checks
"-gnatwe", -- Treat warnings as errors
"-gnat2012", -- Use Ada 2012
"-Wall", -- All GCC warnings
"-O2"); -- Optimise (level 2/3)
end Compiler;
end Hello_World;
If you use GNAT Programming Studio (GPS) as your IDE, you may want to remove the -gnatf flag, as I have experienced that can prevent GPS from parsing the error messages from the compiler.

Related

Compiling C++ code for R (CRAN) packages on Solaris

I am a little bit confused on how to efficiently prepare the R package, so that it will be compatible across all needed system platforms. This is needed so that the new version of package will be accepted by CRAN. The main difficulty comes from compiling external C++ shared library, and optionally CUDA version if the compiler is available. To support this flow I've created specific Makefile, unfortunately using GNU-extensions. It works fine on Linux, OSX and when executed manually via gmake on Solaris. Relevant part is here:
# Checking whether nvcc compiler is available
NVCC_TEST = $(shell basename $(shell which nvcc 2> /dev/null)"")
ifeq ($(NVCC_TEST),nvcc)
ALL_LIBS += libcucubes_gpu.so
ALL_OBJS += $(GPU_OBJS)
ALL_FLAGS += $(GPU_FLAGS)
else
ALL_OBJS += gpu_fallback.o
endif
Turns out that, when running R CMD INSTALL (...) on Solaris, the installation fails on something like this:
make: Fatal error in reader: Makefile, line 39: Unexpected end of line seen
ERROR: compilation failed for package 'libcucubes'
As it turns out, it is caused by the fact that Solaris' version of make is executed instead of GNU-compatible gmake (I've tested it works fine), even though it is available. My question is whether there is any simple way to force usage of gmake here, for the R package build. In general I know I could use autotools to solve compatibility issues during installation, but it seems to bring too much complexity for that simple case. Any advices will be really appreciated, thanks!
If you can't get your build process to use gmake instead of Solaris's pure POSIX make, you can use this hack:
Make a dedicated directory for this hack: mkdir $HOME/make_hack
Softlink gmake asmakein that directory: ln -s /path/to/gmake $HOME/make_hack/make
Set your PATH: PATH=$HOME/make_hack:$PATH
Now, run your build process using that PATH, and it should use gmake. Hopefully it just uses make from its PATH envval and not some hardcoded full path.
Yeah, it's a hack. But it's probably a lot easier than modifying the build process to use gmake instead of make.
From Writing R Extensions:
If you really must require GNU make, declare it in the DESCRIPTION
file by
SystemRequirements: GNU make
and ensure that you use the value of environment variable MAKE (and
not just make) in your scripts.
configure scripts are the preferred solution though. BTW, in general a Makevars file is also preferred over a full Makefile.

How to compile opencl-kernel-file(.cl) to LLVM IR

This question is related to LLVM/clang.
I already know how to compile opencl-kernel-file(.cl) using OpenCL API ( clBuildProgram() and clGetProgramBuildInfo() )
my question is this:
How to compile opencl-kernel-file(.cl) to LLVM IR with OpenCL 1.2 or higher?
In the other words, How to compile opnecl-kernel-file(.cl) to LLVM IR without libclc?
I have tried various methods to get LLVM-IR of OpenCL-Kernel-File.
I first followed the clang user manual.(https://clang.llvm.org/docs/UsersManual.html#opencl-features) but it did not run.
Secondly, I found a way to use libclc.
commands is this:
clang++ -emit-llvm -c -target -nvptx64-nvidial-nvcl -Dcl_clang_storage_class_specifiers -include /usr/local/include/clc/clc.h -fpack-struct=64 -o "$#".bc "$#" <br>
llvm-link "$#".bc /usr/local/lib/clc/nvptx64--nvidiacl.bc -o "$#".linked.bc <br>
llc -mcpu=sm_52 -march=nvptx64 "$#".linked.bc -o "$#".nvptx.s<br>
This method worked fine, but since libclc was built on top of the OpenCL 1.1 specification, it could not be used with OpenCL 1.2 or later code such as code using printf.
And this method uses libclc, which implements OpenCL built-in functions in the shape of new function. You can observe that in the assembly(ptx) of result opencl binary, it goes straight to the function call instead of converting it to an inline assembly. I am concerned that this will affect gpu behavior and performance, such as execution time.
So now I am looking for a way to replace compilation using libclc.
As a last resort, I'm considering using libclc with the NVPTX backend and AMDGPU backend of LLVM.
But if there is already another way, I want to use it.
(I expect that the OpenCL front-end I have not found yet exists in clang)
My program's scenarios are:
There is opencl kernel source file(.cl)
Compile the file to LLVM IR
IR-Level process to the IR
Compile(using llc) the IR to Binary
with each gpu targets(nvptx, amdgcn..)
Using the binary, Run host(.c or .cpp with lib OpenCL) with clCreateProgramWithBinary()
Now, When I compile kernel source file to LLVM IR, I have to include header of libclc(-include option in first one of above command) for compiling built-in functions. And I have to link libclc libraries before compile IR to binary
My environments are below:
GTX960
- NVIDIA's Binary appears in nvptx format
- I'm using sm_52 nvptx for my gpu.
Ubuntu Linux 16.04 LTS
LLVM/Clang 5.0.0
- If there is another way, I am willing to change the LLVM version.
Thanks in advice!
Clang 9 (and up) can compile OpenCL kernels written in the OpenCL C language. You can tell Clang to emit LLVM-IR by passing the -emit-llvm flag (add -S to output the IR in text rather than in bytecode format), and specify which version of the OpenCL standard using e.g. -cl-std=CL2.0. Clang currently supports up to OpenCL 2.0.
By default, Clang will not add the standard OpenCL headers, so if your kernel uses any of the OpenCL built-in functions you may see an error like the following:
clang-9 -c -x cl -emit-llvm -S -cl-std=CL2.0 my_kernel.cl -o my_kernel.ll
my_kernel.cl:17:12: error: implicit declaration of function 'get_global_id' is invalid in OpenCL
int i = get_global_id(0);
^
1 error generated.
You can tell Clang to include the standard OpenCL headers by passing the -finclude-default-header flag to the Clang frontend, e.g.
clang-9 -c -x cl -emit-llvm -S -cl-std=CL2.0 -Xclang -finclude-default-header my_kernel.cl -o my_kernel.ll
(I expect that the OpenCL front-end I have not found yet exists in clang)
There is an OpenCL front-end in clang - and you're using it, otherwise you couldn't compile a single line of OpenCL with clang. Frontend is Clang recognizing the OpenCL language. There is no OpenCL backend of any kind in LLVM, it's not the job of LLVM; it's the job of various OpenCL implementations to provide proper libraries. Clang+LLVM just recognizes the language and compiles it to bitcode & machine binaries, that's all it does.
in the assembly(ptx) of result opencl binary, it goes straight to the function call instead of converting it to an inline assembly.
You could try linking to a different library instead of libclc, if you find one. Perhaps NVidia's CUDA has some bitcode libraries somewhere, then again licensing issues... BTW are you 100% sure you need LLVM IR ? getting OpenCL binaries using the OpenCL runtime, or using SPIR-V, might get you faster binaries & certainly be less painful to work with. Even if you manage to get a nice LLVM IR, you'll need some runtime which actually accepts it (i could be wrong, but i doubt proprietary AMD/NVIDIA OpenCL will just accept random LLVM IR as inputs).
Clang does not provide a standard CL declaration header file (for example, C's stdio.h), which is why you're getting "undefined type float" and whatnot.
If you get one such header, you can then mark it as implicit include using "clang -include cl.h -x cl [your filename here]"
One such declaration header can be retrieved from the reference OpenCL compiler implementation at
https://github.com/KhronosGroup/SPIR-Tools/blob/master/headers/opencl_spir.h
And by the way, consider using this compiler which generates SPIR (albeit 1.0) which can be fed into OpenCL drivers as input.

gprbuild/gprinstall doesn't respect encoding

Building Ada sources for multiple projects, with installing the libraries and sources after each project build, works fine for gnatmake and a gnat.adc containing
pragma Wide_Character_Encoding(UTF8);
but not for gprbuild, no matter what I try.
package Compiler is
for Default_Switches ("ada") use ("-gnatW8");
end Compiler;
or
package Builder is
for Global_Configuration_Pragmas use "gnat.adc";
--The same I used with gnatmake just fine
end Builder;
Am I missing something? When I run a program with projects build with gprbuild I get bracket encoding output instead of the Unicode characters.
The build even has -gnatW8 on the command line. In fact, the command line args during each build are identical, but they produce notably different output when a program is run.
Progress:
Upon noticing the generated files for stand-alone libraries were not built with -gnatW8, I removed all interface declarations for the gpr files, and build standard shared libraries. Programs built with these respect Unicode, and do not output bracket encoded text. So now, the question is why stand-alone libraries aren't obeying the character encoding pragma or flag.

table_editors-moc.ads not found

I'm using gcc (GCC) 4.5.4 20120510 for GNAT GPL 2012 (20120509)
and qtada from qtada-gpl-3.2.0-20120708-3871-qt4.8.2-2.exe installer.
I'm trying to compile example from "..\GNAT\2012\examples\qtada\sql\cached_table", but it say "table_editors-moc.ads not found",
The error came from statement :
with Table_Editors.MOC; pragma Warnings (Off, Table_Editors.MOC);
-- Child package MOC must be included in the executable.
Where can i found the "Child package MOC" that contains "table_editors-moc.ads" and another moc file??
I don't know Qt or QtAda, but a quick search indicates that Qt uses a Meta Object Compiler (MOC) to auto-generate source code from macros. Could it be that your Table_Editor.MOC is supposed to be generated?
I'm surprised that QtAda has installed its examples at \GNAT\2012\examples; judging by the way GNAT is set up on this Mac, I'd have expected \GNAT\2012\share\examples.
However .. I suspect that QtAda's file system layout is complicated enough that you'll need to use a "GNAT Project file" to do the build. I hope there's a .gpr file in the same directory as your example code (if not, I can't help); if so, and assuming it's called cached_table.gpr, then in a command window say
gnatmake -p -P cached_table.gpr
or (following the documentation for QtAda 3.1)
gprbuild -p -P cached_table.gpr

mingw ignores '-L' flag

I am getting linker failures under MinGW, however I cannot see why. This is the link command:
g++ -shared -mthreads
-Wl,--out-implib,C:\Users\camm\Syren\libs\libSy_polyMesh.a -o C:\Users\camm\Syren\libs\Sy_polyMesh.dll debug/Sy_polyMesh.o
debug/moc_Sy_polyMesh.o debug/qrc_Sy_polyMesh.o -L"c:\Qt\4.8.4\lib"
-lglu32 -lopengl32 -lgdi32 -luser32 -LC:\Users\camm\Syren/libs -lSyren -lglew32 -lboost_system -lQtSvgd4 -lQtSqld4 -lQtOpenGLd4 -lQtGuid4 -lQtCored4
The undefined reference errors come from the Syren dll (I should state the command was automatically generated by qmake). The -LC:\Users\camm\Syren/libs looks malformed to me because of the mix of forward and backslashes, but if I manually set them to all one way or the other - it does not change the compiler output.
I had earlier problems with 3rd party libraries I needed (GLEW and Boost specifically), but because they were relatively 'constant' I didn't have a problem putting them in my C:\MinGW\lib directory. But that is really not an option for my plugins.
What I find is that the MinGW docs state in a few locations:
...since suitable search paths may always be specified using -L
options.
...but that GCC itself furnishes the effective defaults, by supplying
appropriate -L options.
However, C:\Users\camm\Syren\libs is where Syren.dll resides!
Edit: Here are the LIBS declarations in my .pro file:
LIBS += -L$(SYREN_PATH)/libs \
-lSyren
win32 {
LIBS += -lglew32 \
-lboost_system
}
And $(SYREN_PATH) expands to C:\Users\camm\Syren. Also I can see to the 'missing' symbols in Syren.dll, for example:
C:\Users\camm\Documents\Syren\Sy_polyMesh_debug/../Sy_polyMesh/src/Sy_polyMesh.cpp:341:
undefined reference to `Sy_GLBuffer::unbind()'
Can be seen listed as:
6c500bd6 T _ZN11Sy_GLBuffer6unbindEv
Edit2
After adding a verbose flag to the linker stage I noticed that the linker was iterating through each search path and then through each library naming convention, and using the first one it could open.
attempt to open C:\Users\camm\Syren/libs/libSyren.dll.a failed
attempt to open C:\Users\camm\Syren/libs/Syren.dll.a failed
attempt to open C:\Users\camm\Syren/libs/libSyren.a succeeded
Hypothesizing that the libSyren.a may be broken, I renamed it to force the linker to use the .dll:
attempt to open C:\Users\camm\Syren/libs/libSyren.dll.a failed
attempt to open C:\Users\camm\Syren/libs/Syren.dll.a failed
attempt to open C:\Users\camm\Syren/libs/libSyren.a failed
attempt to open C:\Users\camm\Syren/libs/Syren.lib failed
attempt to open C:\Users\camm\Syren/libs/libSyren.dll failed
attempt to open C:\Users\camm\Syren/libs/Syren.dll succeeded
But I still get exactly the same error messages!
If you are linking the right DLL and the linker isn't complaining about a missing file, the dll might be missing exports to allow linking.
The MinGW linker can link directly to a DLL if it properly exports the symbols, although it is still recommended to link to the import library (which should be created in a qmake build) which is named lib*.a or lib*.dll.a. I believe the linker looks for variants with and without the libprefix, but I am unsure and should test this myself.
You can check what symbols a DLL exports by using objdump and/or nm.
If the linker doesn't complain about not being able to load Syren dll, it means that the file is correctly loaded... The symbols are just missing into the Syren dll (not exported ?)... Why it's hard to tell without more information
When you built the Syren lib, did you have any warning about missing prototypes ?
What is used by Syren lib, nothing not portable or requiring a Windows dll ?
Could you give the list of missing symbols ?
Edit : How do you compile the Syren.dll ? Did you use Mingw ? What option did you pass to the compiler / linker ?
I suggest to read these 2 links :
http://www.mingw.org/wiki/sampleDLL
http://www.mingw.org/wiki/CreateImportLibraries
If you are exporting C++ function you must use the same compiler between the program and the DLL. Or you could use a C-style wrapper functions to encapsulate the C++ ABI.
A very good article about this subject : http://www.codeproject.com/Articles/28969/HowTo-Export-C-classes-from-a-DLL
What happens when you replace $(SYREN_PATH) with $${SYREN_PATH}?
Because the former notation $() means the contents of an environment variable at the time Makefile is executed.
See the qmake variable reference.

Resources