Set Preproccessor directive for only one program in Automake file - c

Let us assume that we have a source file "a.c".
The "a.c" source file is used in building programs "Prog1","Prog2", and 'Prog3".
"Prog1" also uses source file "x.c"
"Prog2" uses source file "y.c"
"Prog3" uses source file "z.c"
Assume that "a.c" uses a function called "foo()" that is only defined in "x.c". Hence "Prog1" would get built, but "Prog2" and "Prog3" would not compile.
Also assume that "a.c" needs to call function bar1() when building program Prog1, bar2() when building program Prog2, and bar3() when building program Prog3.
How should we create the automake Makefile.am to support this?
I have been trying to specify distinct preprocessor directives when building each program in the automake file "Makefile.am", but so far could not see how it is done.
Any help would be appreciated. Thanks.

Simplest solution? Create three different rules for three different object files all built from the a.c source file.
Then each rule can easily add extra flags needed for the specific build.

bin_PROGRAMS = prog1 prog2 prog3
prog1_SOURCES = a.c x.c
prog1_CPPFLAGS = -DPROG1
prog2_SOURCES = a.c y.c
prog2_CPPFLAGS = -DPROG2
prog3_SOURCES = a.c z.c
prog3_CPPFLAGS = -DPROG3
But to use this you need to make sure you call AM_PROG_CC_C_O in your configure.ac, since a.c is then compiled three times with different options.

Related

How integrate gnatmake/gnatbind/gnatlink in CMake files for C/Ada code?

I wrote a code in a few languages (C, C++, Fortran77, Fortran90) and I can compile it without any sort of problem by using CMake. It works out perfectly.
Now, I would like to add in the main(), which is written in C, some Ada function and I want to compile it by CMake. Given that I am not able to link my Ada function to the main one by using CMake, I get
main.c:(.text.startup+0x16a): undefined reference to adainit
main.c:(.text.startup+0x179): undefined reference to adafunction
main.c:(.text.startup+0x190): undefined reference to adafinal
I did another simplified test by using the main function (written in C) calling the only Ada function, which I coded, and I compiled it by using
gcc -c main.c
gnatmake -c lib_ada.ali
gnatbind -n lib_ada.ali
gnatlink lib_ada.ali main.o -o exe
and it works out. Do you know how I can integrate this approach in a CMakeList.txt?
Note: I think (maybe I mistake) I cannot use the only gnatlink because I need to link all other functions I already have.
Here is reported a minimal reproducible example.
--- main.c ---
#include <stdio.h>
extern int adainit();
extern int adafinal();
extern int Add(int,int);
int main()
{
adainit();
printf ("Sum of 3 and 4 is: %d\n", Add (3,4));
adafinal();
return 0;
}
--- lib_test.adb ---
package body Lib_Test is
function Ada_Add (A, B : Integer) return Integer is
begin
return A + B;
end Ada_Add;
end Lib_Test;
--- lib_test.ads ---
package Lib_Test is
function Ada_Add (A, B : Integer) return Integer;
pragma Export (C, Ada_Add, "Add");
end Lib_Test;
1° test: if you compile by using the following commands:
gcc -c main.c
gnatmake -c lib_test.adb
gnatbind -n lib_test.ali
gnatlink lib_test.ali main.o -o exe
and run ./exe you get Sum of 3 and 4 is: 7.
2° test: I tried to use the following CMake file (CMakeLists.txt) linking the *.a
cmake_minimum_required(VERSION 2.6)
project(Ada2C)
enable_language(C)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -m64")
find_library(TEST_lib lib_test.a PATHS ${CMAKE_CURRENT_SOURCE_DIR})
message(STATUS "Finding library: ${TEST_lib}")
add_executable(TEST_release ${CMAKE_CURRENT_SOURCE_DIR}/main.c)
target_link_libraries(TEST_release ${TEST_lib})
I generate library lib_test.a for the Ada function
gnatmake lib_test.adb
ar rc lib_test.a
I run the cmake and make and I get
main.c:(.text.startup+0x16a): undefined reference to adainit
main.c:(.text.startup+0x179): undefined reference to adafunction
main.c:(.text.startup+0x190): undefined reference to adafinal
More of a comment than an answer, but too long for a comment, so here goes:
Compiling Ada code into your binary means that your binary needs access to the GNAT runtime. This is one thing gnatlink does when you use it to link the final executable. The other thing is the b~<something>.ad{s,b} source gnatbind generates which you need to compile and link against as others mentioned.
The cleanest way to embed Ada in C I've seen so far is to create an encapsulated library. This probably does not make sense if your actual problem is with only one Ada function, but it does with larger chunks of Ada. The encapsulated library will be a shared library that has GNAT's runtime baked in. Being a shared library enables it to implicitly handle initialization during library loading so you don't need adainit() / adafinal() anymore.
The easiest way to create an encapsulated library is to use a ada_code.gpr file:
project ada_code is
for Library_Name use "mylib";
for Library_Dir use "lib";
for Library_Kind use "relocatable";
for Library_Standalone use "encapsulated";
for Library_Auto_Init use "true";
for Library_Interface use ("All", "Packages", "In.Your", "Ada.Code");
for Source_Dirs use ("adasrc");
end ada_code;
In CMake, you can then do:
# tell CMake how to call `gprbuild` on the `.gpr` file.
# you may need to replace `gprbuild` with the absolute path to it
# or write code that finds it on your system.
add_custom_target(compile_mylib
COMMAND gprbuild -P ada_code.gpr)
# copy the library file generated by gprbuild to CMake's build tree
# (you may skip this and just link against the file in the source tree)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/mylib.so
DEPENDS compile_mylib
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_SOURCE_DIR}/lib/mylib.so
${CMAKE_CURRENT_BINARY_DIR}/mylib.so)
# ... snip ...
# link to the copied library
# I am not 100% sure this adds the correct dependency to the custom command.
# You may need to experiment a bit yourself
target_link_libraries(TEST_release ${CMAKE_CURRENT_BINARY_DIR}/mylib.so)
In your C file, you can then delete everything related to adainit() and adafinal().

C - How are c source files incuded without an include statement

I've taken the plunge and am learning C. It's been a pretty good but manageable learning curve coming from a scripting (php, perl) background with only a little bit of C#.
I've used the web-site "Learn C The Hard Way" and am so far grasping reasonably well (I think) but I can't understand this part of one of the exercises:
http://c.learncodethehardway.org/book/ex19.html
He created four source files - object.h, object.c, ex19.h, ex19.c
But I don't understand how the object.c file is included.
The main function is located in ex19.c, and it has the line
#include "ex19.h"
File ex19.h has the line
#include "object.h"
But object.h makes no reference to including object.c. Interestingly object.c contains the line
#include "object.h"
Is there some sort of implied include where if you include the header file, it will automatically include the c source code of the same name?
This is the job of a separate program called the linker. In C, source files need access to the header files of other C source files so that they can see information about what functions, types, and variables are defined by that second C file that the first file might want to use. Each C file is then compiled independently of the rest. The output of the compiler is an object file.
To build a final program, a second program called the linker comes in and combines all the object files together into the overall executable. This program is tasked with taking the implementations of all the different C files and cross-referencing them against one another so that each time one C file references a function or variable in a different C file, that reference can actually be made to the appropriate object.
This is why you don't need to include .c files. Once a source file has a header, it knows enough about the other file in order to use the functions it provides for the compiler to verify that it's using them correctly. The linker then handles of the job of actually making the cross-references. You can think of the compiler as a program that checks to see that if the functions are defined, then the program would work. The linker then actually checks to make sure that those functions are defined in the first place and sets up the appropriate links in the executable.
Hope this helps!
Object.c is not included.
It's compiled as it's own unit and it includes object.h
See the make file:
CFLAGS=-Wall -g
all: ex19
ex19: object.o
clean:
rm -f ex19
ex19: object.o tells you that object.o must be created before ex19 can be built, and this is picked up by default from make file as an object.c exists.
So this make file says
to build all you need ex19, to get ex19 you need object.o, and the to create object.o the makefile picks up object.o built from the object.c
From the page you reference:
make can't see anything in the file for object.o, but it does see an
object.c file, and it knows how to turn a .c into a .o, so it does
that.
The entire logic lies in the makefile and an intelligent compiler. The final binary created has an object file named as object.o which will ideally contain all the function definitions defined in object.h file. It is the linker which links the functions declared in .h file with the definition which are available in .o file.

Calling methods from multiple C files without custom header files, Makefile Linking

This has gotten a bit lost in translation so I am going to be more precise:
we have classes recursion.c, fib.c, and countUp.c. from recursion.c we have to recursively call fib.c or countUp.c, decided by the input argument. I can't use header files and am only given that I must place prototypes:
int fib(int n);
and
void countUp(int n);
My Makefile
TAR = tar
COMPILER_FLAGS = -g -Wall -std=c99 -c
LINKER_FLAGS = -g -o
OBJS = recurse.o
C_FILES = recurse.c fib.c countUp.c
ASM_FILES = recurse.asm
TARGET_FILE = recurse
TARGET_TAR = PA5.tar
$(TARGET_TAR): $(TARGET_FILE)
$(TAR) -cvf $(TARGET_TAR) $(C_FILES) $(ASM_FILES) $(TARGET_FILE) Makefi$
recurse.o: recurse.c
$(C_COMPILER) $(COMPILER_FLAGS) $(C_FILES)
$(TARGET_FILE): $(OBJS)
$(LD_LINKER) $(LINKER_FLAGS) $(TARGET_FILE) $(OBJS)
where fib and countUp class methods must be called recursively. The recursive.c file is considered our c driver. Do not create or implement any header files OTHER than those that are standard c headers (stdio.h, string.h, etc.). When I try to run this I get:
make
gcc -g -o recurse recurse.o
recurse.o: In function `main':
(file root location)/recurse.c:43: undefined reference to `fib'
(file root location)/recurse.c:46: undefined reference to `countUp'
collect2: ld returned 1 exit status
make: *** [recurse] Error 1
Any clue what is going on.
Original Question:
I have multiple C files that I am combining into an executable. For example say I have math.c, the arguments are passed into it, and then if the input argument calls add it performs functions from add.c, if the argument calls subtract it will call functions from subtract.c, etc. The files are then compiled into a .o file, and then an executable is created. The issue I have is not being able to utilize header (.h) files. Is there any way to break into the separate classes or am I missing something? I really don't know exactly how to ask the question, jargon is pretty bad as far as C goes, sorry :(
I don't really get the idea of a driver I guess. (Not a device driver, she keeps telling us this is a c executable driver).
If I understood correctly, what I think you need to do is add the following prototypes above any of the functions you define in recursion.c. The prototypes will allow you to call these functions from within any function inside recursion.c (In fact, including a header file is akin to copy-pasting all of the prototypes defined in the file, as #Justin and #EdS already pointed out)
int fib(int n);
void countUp(int n);
int main() {
...
}
Then you need to make sure that your project file includes the files recursion.c, fib.c, and countUp.c - When you build your project, the linker will do its job and lookup the entry points in your compiled object files, and will proceed to assemble a single executable file.
What compiler are you using?
Including a header file is just a preprocessor directive to include the contents of that file at the location of the include. To achieve the same thing without a header file just copy and paste the code that you would have put in the header file into the top of each c file.
Of course this isn't very maintainable as if you want to change that contents you need to change it in many files, hence why header files exist in the first place.
Since this is homework and considering the fact that you have told us that A) You have no header files to use, and B) you have not been instructed to utilize the extern keyword, it seems to me that your only choice is to include the .c files themselves:
#include "add.c"
#include "subtract.c"
/* etc... */
int main()
{
// use functions defined in "add.c", "subtract.c", etc.
}
Note that this is bad form as you are including the implementation instead of the interface and likely pulling in a bunch of stuff you don't want or need. If that doesn't answer your question then there is something, some instruction from your teacher, missing in the question.

How to use autotools for deep projects?

I have a C project that has the following structure
Main/
Makefile.am
bin/
src/
Makefile.am
main.c
SomeLibrarySource/
SomeFuncs.c
SomeFuncs.h
The main.c contains the main function that uses functions defined in the SomeFuncs.{h/c} files.
I want to use autotools for this project. I read a couple of resources on autotools. But, I was only able to manage using autotools for a single level project where all source, object and other files reside in the same directory.
Then I got some links that talked about using autotools for deep projects like this one and then I got confused.
Right now I have two Makefile.am as follows
Makefile.am
SUBDIRS=src
src/Makefile.am
mainprgdir=../
mainprg_PROGRAMS=main
main_SOURCES=main.c
I am pretty sure that these files should not be as I have them now :P
How do I use autotools for the above project structure? (At least what should be there in those Makefile.am(s) and where should I place them.
EDIT:
One more thing! At the end I would like to have the object files created in the bin directory.
Thanks
mainprogdir=../ does not make a whole lot of sense (you don't know what it is relative to on installation). Probably intended:
# Main/Makefile.am
# .━━ target for `make install`
# |
# ↓ ↓━━ target for compilation
bin_PROGRAMS = bin/main
# ↓━━ based upon compilation target name
bin_main_SOURCES = src/main.c
There are two main approaches. If the functions in SomeLibrarySource are used only by main, then there's no need to build a separate library and you can simply specify the source files in src/Makefile.am
main_SOURCES = main.c SomeLibrarySource/SomeFuncs.c
However, if you actually want to use the functions in other code in your tree, you do not want to compile SomeFuncs.c multiple times but should use a convenience library.
# Assigning main_SOURCES is redundant
main_SOURCES = main.c
main_LDADD = SomeLibrarySource/libSomeFuncs.a
noinst_LIBRARIES = SomeLibrarySource/libSomeFuncs.a
AM_CPPFLAGS = -I$(srcdir)/SomeLibrarySource
(You'll need AC_PROG_RANLIB in configure.ac to use convenience libraries.)
If the source file is named SomeFuncs.c, automake will not need Makefile.am to specify SomeLibrarySource_libSomeFuncs_a_SOURCES, but if the name of the source code file does not match the name specified in noinst_LIBRARIES, SomeLibrarySource_libSomeFuncs_a_SOURCES should be set to the list of files used to build the library. Note that you do not need to specify main_SOURCES, since main.c is the default value if left unspecified (but it's not a bad idea to be explicit.) (In all of this, I am not comfortable use CamlCase names, but the system I'm using uses a case insensitive file system (biggest mistake apple ever made) and the examples I give here are working for me. YMMV)
You could of course do a recursive make, or build the library as a separate project and install it. (I like the final option. Libraries with useful features should exist on their own.)

Creating one C file when compiling multiple sources

I have a set of C files to compile using gcc and make. The build process works fine.
I want to know if I can obtain - during compilation - one C file containing all the source code without any preprocessor macro.
One simple was would be to make a file that included all the other source files.
$cat *.c > metafile.c
This would construct such a file, depending on how you set you 'pragma once' and ifndef's this file would probably not be able to compile on its own.
On the other hand, if what you want in a file where all the preprocessor macro's have been unfolded and evaluated, then the answer is to add the following to gcc:
-save-temps
then the file .ii will contain the unfolded and evaluated macros
If you include all files to the gcc compiler at once you could use
gcc -E main.c other.c another.c
This will also include the stdlib functions maybe use -nostdinc
You can't - normally you invoke the compiler to compile just a single source file, resulting in an object file. Later you call the linker on all of the object files to create the executable - it doesn't have the original C source code available.
You can, however, create a separate shell script that calls gcc with the -E option just to preprocess the source files, and then use the cat utility to put all the sources in a single file.
You can use the -save-temps option to get the intermediate outputs. However it will be one output file per source file. Each source file gets compiled separately and represents a compilation unit which can't be mixed up.
You can also use the -E option, however that will only run the preprocessor and not continue compilation.

Resources