Problem understanding the make utility and the header .h files usage - makefile

I am trying to learn the make command but I am having a little trouble with the way headers are being used
I got prg1.c
#include <stdio.h>
main()
{
printf("Hello World\n");
print();
}
and the prg2.c
#include <stdio.h>
print()
{
printf("Hello World from prg2\n");
}
and here is the make file
objects = prg1.o prg2.o
exe : $(objects)
cc -o exe $(objects)
prg1.o : prg1.c
cc -c prg1.c
prg2.o : prg2.c
cc -c prg2.c
This works perfectly. But if I don't include stdio.h in both file and then I have to compile it using the make, how am I supposed to write the makefile?

If you don't include <stdio.h>, then you can do one of two things:
supply a correct declaration for printf yourself:
int printf(const char *fmt, ...);
There is almost never any reason to do such a thing.
If your compiler is GCC, use the -include compiler option to force the inclusion of "stdio.h":
prg1.o: prg1.c
gcc -c -include stdio.h prg1.c
This is completely hokey; don't do it.
Note that the make utility has nothing to do with ensuring that the correct header material is included in C translation units. make is a utility which runs shell commands in response to some files not existing or having modification stamps older than other files.

Related

How is automatic dependency generation with GCC and GNU Make useful?

I found many ways online to use the -M-type flags for GCC (or G++) to automatically generate dependencies in your Makefile. All approaches seem similar, I implemented this one.
All arguments I could find in favor are along the lines of: It helps you in that you don't have to manage dependencies manually.
I don't see why.
Consider the following files:
main.c
#include "foo.h"
int main() { foo(); return 0; }
foo.h
void foo();
foo.c
#include "foo.h"
void foo() { ... }
I would say that main.c depends on foo. However, when I run make main.o, foo is not built. The dependency file main.d contains (which explains why foo has not been built):
main.o: main.c foo.h
foo.h:
Now if I were to create an executable (e.g. app: ; $(CC) -o app main.c, with or without auto-dependency generation flags), I would still have to manually specify that it depends on foo.o.
So my question is: how does the auto-dependency generation save me any work if I still have to specify the dependency on foo.o?
No, main.c does not depend on foo. To be more exact main.c does not depend on anything but the text editor. It's the main.o that depends on main.c and foo.h as those files are required to compile main.o. Your final binary should depend on main.o and foo.o to be linked together, but it needs to be explicitly stated - neither make nor linker will find out what files you want to build together.
What this autodependency gives you is the notation that when foo.h changes, main.o will need to be recompiled (as this is included from main.c) even though main.c itself did not have any changes.
"I would say that main.c depends on foo."
Not quite; main.o depends on foo.h, and app depends on foo.o.
Automatic dependency generation can take care of that first dependency; the compiler finds #include "foo.h" in main.c and takes note of it.
The second dependency you must take care of. Neither the compiler nor Make can deduce it. (Bear in mind that not every header file has a corresponding source file with a matching name.)

How to compile a file using a shared library?

I am trying to compile a source given a .so file libfoo.so. The only thing in this library is a function that just returns a number (yeah, I know, advanced stuff). The header file equivalent (I was provided with both, but am only supposed to use the .so) is named foo.h and the function is named int foo().
My source file is main.c:
#include <stdio.h>
#include "foo.h"
int main()
{
int x = foo();
printf("%d", x);
return 0;
}
Now, when trying to compile I have the following commands:
gcc -Wall -fPIC -c main.c -o main.o
gcc -Wall -fPIC main.o -o main -lfoo -L.
The first command fails to create the object file, outputting the following error:
fatal error: foo.h: No such file or directory
I am using Ubuntu 16.04.
I have also tried exporting the current location to LD_LIBRARY_PATH as I've seen suggested on a few other answers.
export LD_LBIRARY_PATH=$LD_LIBRARY_PATH:machine/Desktop/lib_test
You need to have the interface definition from the .h file and that file must be in the current directory or a directory on the include search path.
Note that on some systems filenames and paths are case dependent.

Linking gnu libraries c++ and fortran

I have spent the day searching for an answer to what should be a simple problem. I am building a c++ program to call a fairly large amount of existing fortran. I started by changing the fortran main to a subroutine and then called it with a simple c++ main. My steps look like:
gfortran -c f1.f90 f2.f90 ......
g++ -c mn.cpp
gfortran -lstdc++ -o prog.exe mn.o f1.o ....
mn.cpp started out looking like the code below, and the above steps do work ok. I get a host of linker errors if I try to link with:
g++ -lgfortran (this never works!)
Next, I tried to instantiate a simple array class (remove the 2 commented lines). This produced linker errors concerning gxx_personality_seh0, vtable, and operator new.I get similar errors if I just create an array of doubles with new (remove comment), and if I remove the call to the fortran program completely (still linking with gfortran). Obviously, -lstdc++ does not bring in all the libraries needed. Which libraries are needed and how can I get it to link them?
I am using Windows 7 with Cygwin. The libraries it links are in ...lib/x86_64-pc-cygwin/4.9.3. I can post the linker output if it would be helpful.
mn.cpp which works (code commented out) is below:
#include <string.h>
#include <stdlib.h>
//#include "array.h"
extern "C" {
void mnf90_(const char*,int);
}
int main(int argc, char* argv[]){
// Array2D A; // first derivative
static const char *feos = "d/fld9x.dat";
int npoint = 20;
// double *xc = new double[npoint];
mnf90_(feos,strlen(feos));
}

calling functions from a different c file

actually I was compiling with multiple files. Following are the files:
file main.c -->
#include <stdio.h>
void foo3(void)
{
printf("INSIDE foo3 function\n");
}
int main()
{
foo1();
foo2();
foo3();
}
file 1.c -->
#include <stdio.h>
void foo1(void)
{
printf("INSIDE foo1 function\n");
}
file 2.c-->
#include <stdio.h>
void foo2(void)
{
printf("INSIDE foo2 function\n");
}
Now I compiled using gcc as follows-->
gcc 1.c 2.c main.c -o main
following was the output -->
INSIDE foo1 function
INSIDE foo2 function
INSIDE foo3 function
My doubt is how could main() call foo1() and foo2() when they are not declared in main.c. But now if I change main.c as follows ( writing the definition of foo3() after main()) like this:
edited main.c -->
#include <stdio.h>
int main()
{
foo1();
foo2();
foo3();
}
void foo3(void)
{
printf("INSIDE foo3 function\n");
}
and then if I compile I get this error:
main.c:9:6: warning: conflicting types for ‘foo3’ [enabled by default]
void foo3(void)
^
main.c:6:2: note: previous implicit declaration of ‘foo3’ was here
foo3();
^
why was this error not shown earlier in case of foo1() and foo2() . Thankyou in advance.
My doubt is how could main() call foo1() and foo2() when they are not declared in main.c
Because the GCC compiler defaults to the old ANSI C (aka as C89) language, where undeclared functions are permitted and defaults to giving int result.
Try to invoke the compiler as e.g.
gcc -std=c99 -Wall -g -c main.c
or (if you want to compile all files at once)
gcc -std=c99 -Wall -g 1.c 2.c main.c -o main
You could ask for link time interprocedural optimizations with gcc -flto instead of gcc using a recent GCC, e.g. GCC 4.9 in september 2014.
This would want a C99 conforming source code where all functions should be declared.
The -Wall asks for (almost) all warnings. The -g option produces a debuggable object code (or executable for the last command compiling all files at once).
In your edited main.c when foo3 first occurrence (inside main) is encountered, the compiler guesses that it is a function returning int. When the compiler sees the definition of foo3 it rightly complains.
You could use the -Wstrict-prototypes warning option to gcc (but it is implied by -Wall which I always recommend using).
At link time, the type (and signature) of C functions does not matter. The linker just uses name to do its job (but C++ use name mangling). Of course, calling a function with the incorrect arguments or result is undefined behavior.
The good conventional practice is to have a common header file declaring all the used and public functions and types (and constants) and include that header file in your source files (this avoids to have to copy and paste these declarations several times). So you whould have a new header file myheader.h like
// file myheader.h
#ifndef MY_HEADER_INCLUDED
#define MY_HEADER_INCLUDED
void foo1(void);
void foo2(void);
void foo3(void);
#endif /*MY_HEADER_INCLUDED*/
and you would add #include "myheader.h" in all your source files (after the #include <stdio.h> directive there). Notice the include guard trick with MY_HEADER_INCLUDED.
In practice, header files usually contain comments explaining the API of your program.
Learn also about GNU make. It will ease the building of your multi-source code files programs (you just compile and build by running make). See this and that examples of Makefile. Understand that C preprocessing is the first phase of C compilation.

MakeFile Example

main.c: simple 'driver' program to call the 'sayHello()' function in the hello module. Note that since main.c does not call any standard I/O
library functions, it should not have #include stdio.h
hello.h: provides the prototype for the sayHello() function; don't forget
the include guard
hello.c: implements the sayHello() function. This is the only file that has
#include stdio.h
Here is my Makefile: (w/o the 'pack' part)
hello: hello.o main.o
gcc main.o hello.o -o hello
main.o: main.c hello.h
gcc -c main.c -o main.o
hello.o: hello.c hello.h
gcc -c hello.c -o hello.o
test: hello
./hello
clean:
rm -f *.o hello
My hello.c file is:
#include<stdio.h>
#include "main.c"
int main()
{
sayHello();
return 0;
}
My hello.h file is:
void sayHello(void);
My main.c file is:
#include "hello.h"
void sayHello(void)
{
puts("Hello,World!");
return;
}
I did a test with this and it displayed "Hello, World!". But when I ran it again just in case, there were errors. Any ideas what could have happened?
hello.c and hello.h are some kind of library. hello.h provides sayHello() function to the world and this function is implemented in hello.c. That means that hello.c must have following include:
#include "hello.h"
and
#include <stdio.h>
main.c should only have:
#include "hello.h"
I think "guard" should be a function prototype in hello.h:
void sayHello(void);
You seem to be asking several questions without realizing it.
Let's look at it one by one. Your assignment is to make a project, separate the program which calls a function and the implementation of the function into separate pieces of source code. That's why you have the restriction on #include and the specification of the include file. You're also asked to generate a Makefile to compile the various source code files into a single program and provide basic facilities like compressing source code into a zip file or removing the object files. The assignment is meant to acquaint you with modular and automated compilation and separation of functions into distinct pieces.
If you want to learn about programming the best thing you can do is invest some effort into looking at simple make files and compilation. I could give you the answer but won't until you've tried for a while. You'll learn more from failed attempts than peeking at the answers.
In short, you have to first create the source code, figure out how to separate the sayHello function and the main function into two different source files and export the function definition through the include file. The second problem you have is the design of the make file, which your assignment pretty much specifies, all you have to do is learn about the make file configuration language and re-write the human worded specification into the make format. You'll benefit from searching for "makefile tutorial" and reading the first handful of results. ... I'm assuming you want to learn all of this and not just get the answers for no work. Although make files can be tricky, the good news is that at this level they're pretty trivial.
PS Try looking here: http://mrbook.org/tutorials/make/

Resources