I'm working on a personal project with Rust and tcl but i still want to use the classic makefile structure.
I know that to compile multifile I just need to declare mod second on main.rs and rustc automatically connect the modules. So I use
$ rustc main.rs -o output -C debuginfo=2
Now I tried to integrate autoconf and automake because I want to make a configure script to check for tcl, rustup etc... But I don't know how to edit to compile with rustc and its options insead of cc and c options (like trying a .o that doesn't compile because they don't have a main function).
for the configure.ac i used:
AC_CONFIG_SRCDIR([source/main.rs])
AC_CONFIG_AUX_DIR(config)
# I manually checked for rustup and tclsh
AM_INIT_AUTOMAKE
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
for the Makefile.am:
AUTOMAKE_OPTIONS = foreign
bin_PROGRAMS = output
SUBDIRS = sources
output_SOURCES = sources/main.rs
I have the main directory with configure.ac and Makefile.am and the sources directory with all the stuff (and also the config directory for autoconf)
Now I tried to integrate autoconf and automake because I want to make a configure script to check for tcl, rustup etc...
The configure script is the responsibility of Autoconf. It is not obligatory to use Automake together with Autoconf, and you should consider whether it would be sensible for you to use Autoconf alone. That would give you complete control over the generated Makefile, as you would write a Makefile.in directly instead of relying on Automake to do that for you. Presumably, you would write a much simpler Makefile.in than Automake generates, and that's fine.
Automake is not necessarily out of the question, but its manual has this to say about language support:
Automake currently only includes full support for C, C++ (see C++
Support), Objective C (see Objective C Support), Objective C++ (see
Objective C++ Support), Fortran 77 (see Fortran 77 Support), Fortran
9x (see Fortran 9x Support), and Java (see Java Support with gcj).
There is only rudimentary support for other languages, support for
which will be improved based on user demand.
Some limited support for adding your own languages is available via
the suffix rule handling (see Suffixes).
The referenced section about suffix rules shows how you might use such a rule to teach Automake how to build Rust programs. It might look something like this:
.rs:
$(RUSTC) $< -o $# $(AM_RUSTFLAGS) $(RUSTFLAGS)
SUFFIXES = .rs
That assumes that configure will identify the Rust compiler and export its name as RUSTC. AM_RUSTFLAGS is for defining compilation flags internally in your project (typically in your Makefile.am), and RUSTFLAGS is for the builder to add or override compilation flags at build time.
But since the compiler does not produce intermediate object files (or so I gather), I would expect that defining sources in output_SOURCES would not yield a working Makefile, and that you would probably need the name of the top-level Rust source to match the name of the wanted binary (i.e. output.rs instead of main.rs). The single-suffix rule should, then, get your binary built without any sources being explicitly specified. You would also want to name all contributing Rust sources in the EXTRA_SOURCES variable, else they would be omitted from distribution packages built via make dist.
Note, too, that the above does not define all the build dependencies that actually exist if you're building multifile programs. I would suggest doing that by adding an appropriate prerequisite-only rule, such as
output: $(output_extra_sources)
(with no recipe) in multifile cases. This will ensure that make will recognize when output needs to be rebuilt as a result of a modification to one of its sources other than output.rs.
Related
GCC's cross compiling autotools is supposed to be flexible, but I've isolated a bug that's been breaking cross compiler builds that ought to work.
Note: Some systems will "poison" default compiler tool names to prevent using wrong tools by default. On my system, x86_64-pc-gnu-linux-ar will execute but "ar" is not found.
I need to build cross compiler toolchains with custom names. gcc's configure script supports this with --program-prefix or --program-transform-name. However, when using a custom name, all compile time tools have to be explicitly named on the configure line. gcc configure is not intelligent enough to find tools it has just built with a name change. (too stupid).
The GCC manual states how to explicitly name tools:
configure AR=x86_foo_b_ar AR_FOR_TARGET=ARMv6m_foo_b_ar ...
However, it doesn't work right. Autoools sometimes ignores the supplied names and the build fails. In particular, it ignores 'AR' and 'OBJDUMP' variables.
Apparently the toplevel gcc configure was created at a later date than lower level configures.
Makefile.in without Makefile.am in GCC?
Makefile.am does not exist in some subdirectories, but it does exist in newer subdirectories.
This causes inconsistencies in variable passing from the top-level makefile.
Internally, the top level "configure" script has variables AR_FOR_HOST (alias for AR), AR_FOR_BUILD, and AR_FOR_TARGET. These variables are used to re-define "AR" when entering sub-directories to force a generic make script to compile for a particular target.
I've even gone so far as to define the internal variables correctly as well as "AR" and "OBJDUMP" on the configure command line. ( Shouldn't be needed ).
gcc-7.3.0/configure --host=x86_64-pc-linux-gnu --program-prefix=armv6m-softfloat-eabi-newlib- AR_FOR_BUILD=/usr/bin/x86_64-pc-linux-gnu-ar AR=/usr/bin/x86_64-pc-linux-gnu-ar AR_FOR_HOST=/usr/bin/x86_64-pc-linux-gnu-ar AR_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/ar AS_FOR_BUILD=/usr/bin/x86_64-pc-linux-gnu-as AS=/usr/bin/x86_64-pc-linux-gnu-as AS_FOR_HOST=/usr/bin/x86_64-pc-linux-gnu-as AS_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/as DLLTOOL_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/dlltool LD_FOR_BUILD=/usr/bin/x86_64-pc-linux-gnu-ld LD=/usr/bin/x86_64-pc-linux-gnu-ld LD_FOR_HOST=/usr/bin/x86_64-pc-linux-gnu-ld LD_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/ld LIPO_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/lipo NM_FOR_BUILD=/usr/bin/x86_64-pc-linux-gnu-nm NM=/usr/bin/x86_64-pc-linux-gnu-nm NM_FOR_HOST=/usr/bin/x86_64-pc-linux-gnu-nm NM_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/nm OBJCOPY_FOR_BUILD=/usr/bin/x86_64-pc-linux-gnu-objcopy OBJCOPY=/usr/bin/x86_64-pc-linux-gnu-objcopy OBJCOPY_FOR_HOST=/usr/bin/x86_64-pc-linux-gnu-objcopy OBJCOPY_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/objcopy OBJDUMP_FOR_BUILD=/usr/bin/x86_64-pc-linux-gnu-objdump OBJDUMP=/usr/bin/x86_64-pc-linux-gnu-objdump OBJDUMP_FOR_HOST=/usr/bin/x86_64-pc-linux-gnu-objdump OBJDUMP_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/objdump RANLIB_FOR_BUILD=/usr/bin/x86_64-pc-linux-gnu-ranlib RANLIB=/usr/bin/x86_64-pc-linux-gnu-ranlib RANLIB_FOR_HOST=/usr/bin/x86_64-pc-linux-gnu-ranlib RANLIB_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/ranlib READELF_FOR_BUILD=/usr/bin/x86_64-pc-linux-gnu-readelf READELF=/usr/bin/x86_64-pc-linux-gnu-readelf READELF_FOR_HOST=/usr/bin/x86_64-pc-linux-gnu-readelf READELF_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/readelf STRIP_FOR_BUILD=/usr/bin/x86_64-pc-linux-gnu-strip STRIP=/usr/bin/x86_64-pc-linux-gnu-strip STRIP_FOR_HOST=/usr/bin/x86_64-pc-linux-gnu-strip STRIP_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/strip CC_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/cc CXX_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/cxx WINDRES_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/windres WINDMC_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/windmc --target=armv6m-softfloat-eabi --build=x86_64-pc-linux-gnu --prefix=/usr --bindir=/usr/x86_64-pc-linux-gnu/armv6m-softfloat-eabi-newlib/gcc-bin/7.3.0 --includedir=/usr/lib/gcc/armv6m-softfloat-eabi-newlib/7.3.0/include --datadir=/usr/share/gcc-data/armv6m-softfloat-eabi-newlib/7.3.0 --mandir=/usr/share/gcc-data/armv6m-softfloat-eabi-newlib/7.3.0/man --infodir=/usr/share/gcc-data/armv6m-softfloat-eabi-newlib/7.3.0/info --with-gxx-include-dir=/usr/lib/gcc/armv6m-softfloat-eabi-newlib/7.3.0/include/g++-v7 --with-python-dir=/share/gcc-data/armv6m-softfloat-eabi-newlib/7.3.0/python --enable-languages=c --enable-obsolete --enable-secureplt --disable-werror --with-system-zlib --enable-nls --without-included-gettext --enable-checking=release --with-bugurl=https://bugs.gentoo.org/ --with-pkgversion=Gentoo 7.3.0-r3 p1.4 --disable-esp --enable-poison-system-directories --disable-bootstrap --with-newlib --enable-multilib --disable-altivec --disable-fixed-point --with-float=soft --disable-libgcj --disable-libgomp --disable-libmudflap --disable-libssp --disable-libcilkrts --disable-libmpx --disable-vtable-verify --disable-libvtv --disable-libquadmath --enable-lto --without-isl --disable-libsanitizer --enable-default-pie --enable-default-ssp
I'm wanting gcc to both make and use tools that start with the prefix: armv6m-softfloat-eabi-newlib-
(Arm cortex m0 chipset is what I am using)
But "make" still fails when attempting to execute "ar" in the .../libcpp directory. The reason is that .../libcpp/Makefile.in is not updated by automake. It's a hand crafted file. On line 28 of the old .../libcpp/Makefile.in it says "AR = ar"
So, the AR variable is hardcoded to "ar" But, "ar" doesn't exist on my system. I've tried editing .../libcpp/Makefile.in with "AR = dummyname" , and the build crashes with "can't fine dummyname" instead of can't find "ar". So, the bug is on line 28.
All other variables in the .../libcpp/Makefile.in are of the form:
CC = #CC#
INSTALL = #INSTALL#
etc..
On a positive note: The compiler used by .../libcpp IS the fully qulaified name I gave to gcc-7.3.0/configure. That success made me think I could fix the bug by editing the makefile to read:
AR = #AR#
But the build fails with "Can't find AR#"
I'm not familiar enough with autotools to hand edit the Makefile.in and fix the bug.
What's the #variable# name format do?
Does the configure.ac in the subdirectory have to define "AR" in some way for #AR# to be linked to the value in the toplevel directory?
I've tried a few other tests while building different gcc versions. Re-running autoconfig, automake, is hell because GCC uses AC_PREREQ() macro.
For example, I have autotools 2.69 installed ... but gcc 7.3.0 fails and complains that I must use autotools 2.64, ONLY. eg: AC_PREREQ(2.64)
So, fixing the bug via autotools doesn't seem practical.
I'm hoping to simply patch the .../libcpp/Makefile.in, since that file is exactly the same in so many versions of gcc.
Questions:
Why is "ar" hard-coded ? Is this a serious legacy issue? and what is a minimal patch that won't interfere with other configurations of GCC?
Is it better to modify the shell or the Makefile; eg: like the top level configure shell script could define a bash function that would be inherited by make as "if" it were a program.
if [ -z ${AR##*-*} ] ; then
ar() { $AR }
fi
Edit: A quick-fix patch for gcc-7.3.0
This is not a "correct" fix, but just a work-around.
I've found three places where the sub-directories ignore variables passed in from the toplevel configure.
.../libcpp/Makefile.in on line 29
.../gcc/configure just before line 29531
.../libcc1/configure just before 14574
The second and third errors are from a defective macro in configure.ac. I haven't traced it back because I can't run autoconfig anyway.
I added a line to the configure(s), to see if passing the default OBJDUMP override variable would allow gcc to compile. It does. I'm not sure I've chosen the right override variable for all cases of gcc compile switches, but at least it proves where the bug is.
Patch file follows:
--- gcc-old/libcpp/Makefile.in
+++ gcc-new/libcpp/Makefile.in
## -28,3 +28,3 ##
INSTALL = #INSTALL#
-AR = ar
+AR ?= ar
ARFLAGS = cru
--- gcc-old/gcc/configure
+++ gcc-new/gcc/configure
## -29531,4 +29531,6 ##
;;
esac
+ if [ -n $OBJDUMP ]; then export_sym_check="$OBJDUMP -T"; fi
+
if test x"$enable_plugin" = x"yes"; then
--- gcc-old/libcc1/configure
+++ gcc-new/libcc1/configure
## -14574,4 +14574,6 ##
;;
esac
+ if [ -n $OBJDUMP ]; then export_sym_check="$OBJDUMP -T"; fi
+
if test x"$enable_plugin" = x"yes"; then
TL;DR: there are a lot of things you could try, but the very first would be to specify AR on the command line when you run make:
make AR=x86_foo_b_ar
That shouldn't be necessary when you've already specified the same to configure, but if it doesn't work then that suggests a problem one or more levels up from the Makefile.in you're looking at. Variable definitions specified on the make command line override definitions in makefiles.
"make" still fails when attempting to execute "ar" from the .../libcpp directory. The reason is that .../libcpp/Makefile.in is not updated by automake. It's a hand crafted file.
To be clear, since understanding the system you are trying to use is immensely helpful in troubleshooting it, automake does not run at configuration or build time. It is used by the package maintainer to build one or more Makefile.in files to be included in source distributions, such as the one you obtained. Of course, this is not the only way to create Makefile.in files, and the configure script does not care how you create them (or other input files).
I'm not familiar enough with autotools to hand edit the Makefile.in and fix the bug. What's the #variable# name format do?
Does the configure.ac in the subdirectory have to define "AR" in some way for #AR# to be linked to the value in the toplevel directory?
The #variable# construction is used for values that are expected to be substituted by the configure script when it builds a corresponding output file. For that to take place, there needs to be at least a corresponding AC_SUBST([variable]) or its equivalent in the configure.ac (sometimes named configure.in, instead). Normally, that's preceded somewhere in configure.ac by code assigning an appropriate value to shell variable variable.
If you modify configure.ac then you need to rebuild the configure script, and in that case it's probably safest to rebuild the whole build system, as a package maintainer would do. There may be a script provided for that purpose in the package (autogen.sh is a common name for such scripts), but the default mechanism is to run the Autotools program autoreconf in the top-level directory of the project source tree.
I've tried a few other tests while building different gcc versions.
Re-running autoconfig, automake, is hell because GCC uses AC_PREREQ()
macro.
For example, I have autotools 2.69 installed ... but gcc 7.3.0 fails
and complains that I must use autotools 2.64, ONLY. eg:
AC_PREREQ(2.64)
That description is not consistent with the documentation of AC_PREREQ, nor with my experience with that macro. AC_PREREQ tests for the specified Autoconf version or newer. It does not demand an exact Autoconf version. There may be something else in the build system that does so, but it's not AC_PREREQ.
In any case, one alternative would be to obtain and install Autoconf 2.64. You may even be able to install it alongside your existing version. Some systems even provide pre-built packages for exactly that purpose.
So, fixing the bug via autotools doesn't seem practical. I'm hoping to
simply patch the .../libcpp/Makefile.in, since that file is exactly
the same in so many versions of gcc.
Patching a Makefile.in does not require afterward re-running the autotools, so it's at least conceivable that that would work. Even for Makefile.in files that were generated by Automake. You could consider having a look at how AR is defined in some of the Automake-generated Makefile.in files in the project (supposing there are any) for an idea of how it should look.
Why is "ar" hard-coded ? Is this a serious legacy issue?
I can only speculate. As a threshold matter, I'm inclined to suppose that in that Makefile, the archiver of the build system is the one wanted (not that of the intended host system, nor a cross-ar for host-target). It is reasonable in that case for AR = ar to be provided as a default, because that can be overridden via a declaration of that variable on the command-line.
That you are in fact not getting the AR you specify to configure looks like a bug to me -- probably a regression introduced at some point when some of the higher-level bits of the build system were updated. I have no trouble imagining such an issue slipping by, as a system configuration such as yours, in which the system's own archiver goes only by a non-standard name, is very uncommon.
and what is a
minimal patch that won't interfere with other configurations of GCC?
The first thing to try is to pass the AR definition on the top-level make command line:
make AR=x86_foo_b_ar
Such definitions will be passed on to recursively-invoked sub-makes, and definitions on the command line (but not, by default, from the environment) override definitions in Makefiles.
Is it better to modify the shell or the Makefile; eg: like the top
level configure shell script could define a bash function that would
be inherited by make as "if" it were a program.
The top-level configure script could be modified to define a shell function and export it to child processes, but not to its parent or siblings. This is nothing specific to configure; the shell just doesn't work that way. Whatever changes you make, if any, would be best made in Makefile.in files before running configure, or in the generated Makefiles afterward.
I've added code to an existing large application and need to make GLib a requirement, as my code relies on it. For development, I just manually edited the Makefile to add
-lglib-2.0
To the LIBS= variable and
-I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include $<
to the line starting with ${CC}.
However, I am at a loss for how to make this permanent/portable in the app -- i.e. when someone executes ./configure in the future, the resulting Makefile should also include the above (as appropriate, since these depend on pkg-config output, I've learned). The codebase I updated includes the following files from the gnu tool chain:
Makefile.in
Makefile.manual
config.h.in
configure
configure.in
I only have a handful of CS degrees and a few years of development experience, so the GNU toolchain remains utterly impenetrable to me. :-/ From googling around, I'm under the impression there should also be a configure.ac file or something where I should add a macro for requiring glib, but no such file is included in the package and I'm at the point of learned helplessness with the whole automake/autoconf/configure/makefile business. Thanks in advance for any advice or pointers!
You should not edit any generated files manually. This includes the final Makefile used to build the application.
In configure.ac, every dependency is listed, thus checking for GLib should go in there. From this file, your final configure shell script is generated.
GLib provides a pkgconfig description so you almost always want to use this to get the correct compile and link flags.
Combining pkgconfig and Autotools is just a matter of calling the PKG_CHECK_MODULES macro. The Autotools Mythbuster is an excellent source that describes how to do it.
In the end it boils down to adding these lines to your configure.ac:
PKG_PROG_PKG_CONFIG
PKG_CHECK_MODULES([GLIB], [glib-2.0])
and these lines to your Makefile.am:
foo_CXXFLAGS = $(GLIB_CFLAGS)
foo_LIBS = $(GLIB_LIBS)
I wanted to know why autoconf and automake (auto tools) are used to Build the Gstreamer(and odes like gstramer).
These I suppose are used to generate the Makefiles which then can be used by simply running make command.
What are makefile.am and configure.ac files .
Rgds,
Softy
Makefile.am is an Automake script shorthand for writing makefiles. It's processed by Automake to generate Makefile.in. It's easier to use Automake language to specify dependencies and standard targets required by the GNU Build System.
Makefile.in is a makefile that is missing platform-dependent code. See below.
configure.ac is a file, written in the M4 macro language. It is processed by Autoconf to generate a shell script called configure. It is much easier and less error-prone to write configure.ac than writing a 200k shell script.
configure is a shell script that checks whether your platform supports all sorts of portable and nonportable features. It generates a whole bunch of files. It can also put platform-dependent and system-dependent code into files (usually ending with *.in), transforming them into the same file without the .in extension. Specifically, it generates Makefile from Makefile.in.
The flow diagram on this Wikipedia page may be helpful.
I have a program and I want to measure it performance but using gprof.now I want to add a -pg flag in it. I have many different files makefile.am makefile.in configure
I install the program using following steps
./configure
make
make install
Now I have read somewhere that:
automake gererates Makefile.in from Makefile.am
configure generates Makefile from Makefile.in
I am totally confused and want to ask two question
In which file and where do I add -pg flag? In makefile.in or makefile.am as they both have different types of flag options?
If configure generates makefile from makefile.in and automake generates makefile.in from makefile.am then shoud'nt we be using make before ./configure? what the hierarchy?
man gcc:
-pg Generate extra code to write profile information suitable for the
analysis program gprof. You must use this option when compiling
the source files you want data about, and you must also use it when
linking.
It says it needs to be in CPPFLAGS (used for both C and C++ code) and LDFLAGS (unless non-standard variables are used). The standard way is to pass flags to configure script:
$ ./configure CPPFLAGS=-pg LDFLAGS=-pg
The last sentence in the article caught my eye
[F]or C/C++ developers and
students interested in learning to
program in C/C++ rather than users of
Linux. This is because the compiling
of source code is made simple in
GNU/Linux by the use of the 'make'
command.
I have always used gcc to compile my C/C++ programs, whereas javac to compile my Java programs. I have only used make to install programs to my computer by configure/make/make install.
It seems that you can compile apparently all your programs with the command make.
What is the difference between make and gcc?
Well ... gcc is a compiler, make is a tool to help build programs. The difference is huge. You can never build a program purely using make; it's not a compiler. What make does it introduce a separate file of "rules", that describes how to go from source code to finished program. It then interprets this file, figures out what needs to be compiled, and calls gcc for you. This is very useful for larger projects, with hundreds or thousands of source code files, and to keep track of things like compiler options, include paths, and so on.
gcc compiles and/or links a single file. It supports multiple languages, but does not knows how to combine several source files into a non-trivial, running program - you will usually need at least two invocations of gcc (compile and link) to create even the simplest of programs.
Wikipedia page on GCC describes it as a "compiler system":
The GNU Compiler Collection (usually shortened to GCC) is a compiler system produced by the GNU Project supporting various programming languages.
make is a "build tool" that invokes the compiler (which could be gcc) in a particular sequence to compile multiple sources and link them together. It also tracks dependencies between various source files and object files that result from compilation of sources and does only the operations on components that have changed since last build.
GNUmake is one popular implementation of make. The description from GNUmake is as follows:
Make is a tool which controls the generation of executables and other non-source files of a program from the program's source files.
Make gets its knowledge of how to build your program from a file called the makefile, which lists each of the non-source files and how to compute it from other files.
gcc is a C compiler: it takes a C source file and creates machine code, either in the form of unlinked object files or as an actual executable program, which has been linked to all object modules and libraries.
make is useful for controlling the build process of a project. A typical C program consists of several modules (.c) and header files (.h). It would be time-consuming to always compile everything after you change anything, so make is designed to only compile the parts that need to be re-compiled after a change.
It does this by following rules created by the programmer. For example:
foo.o: foo.c foo.h
cc -c foo.c
This rule tells make that the file foo.o depends on the files foo.c and foo.h, and if either of them changes, it can be built by running the command on the second line. (The above is not actual syntax: make wants the commands indented by a TAB characters, which I can't do in this editing mode. Imagine it's there, though.)
make reads its rules from a file that is usually called a Makefile. Since these files are (traditionally) written by hand, make has a lot of magic to let you shorten the rules. For example, it knows that a foo.o can be built from a foo.c, and it knows what the command to do so is. Thus, the above rule could be shortened to this:
foo.o: foo.h
A small program consisting of three modules might have a Makefile like this:
mycmd: main.o foo.o bar.o
$(CC) $(LDFLAGS) -o mycmd main.o foo.o bar.o
foo.o: foo.h bar.h
bar.o: bar.h
make can do more than just compile programs. A typical Makefile will have a rule to clean out unwanted files:
clean:
rm -f *.o core myapp
Another rule might run tests:
check: myapp
./myapp < test.input > test.output
diff -u test.correct test.output
A Makefile might "build" documentation: run a tool to convert documentation from some markup language to HTML and PDF, for example.
A Makefile might have an install rule to copy the binary program it builds to wherever the user or system administrator wants it installed.
And so on. Since make is generic and powerful, it is typically used to automate the whole process from unpacking a source tarball to the point where the software is ready to be used by the user.
There is a whole lot of to learn about make if you want to learn it fully. The GNU version of make has particularly good documentation: http://www.gnu.org/software/make/manual/ has it in various forms.
Make often uses gcc to compile a multitude of C or C++ files.
Make is a tool for building any complex system where there are dependancies between the various system components, by doing the minimal amount of work necessary.
If you want to find out all the things make can be used for, the GNU make manual is excellent.
make uses a Makefile in the current directory to apply a set of rules to its input arguments. Make also knows some default rules so that it executes even if it doesn't find a Makefile (or similar) file in the current directory. The rule to execute for cpp files so happens to call gcc on many systems.
Notice that you don't call make with the input file names but rather with rule names which reflect the output. So calling make xyz will strive to execute rule xyz which by default builds a file xyz (for example based on a source code file xyz.cpp.
gcc is a compiler like javac. You give it source files, it gives you a program.
make is a build tool. It takes a file that describes how to build the files in your project based on dependencies between files, so when you change one source file, you don't have to rebuild everything (like if you used a build script). make usually uses gcc to actually compile source files.
make is essentially an expert system for building code. You set up rules for how things are built, and what they depend on. Make can then look at the timestamps on all your files and figure out exactly what needs to be rebuilt at any time.
gcc is the "gnu compiler collection". There are many languages it supports (C, C++, Ada, etc depending on your setup), but still it is just one tool out of many that make may use to build your system.
You can use make to compile your C and C++ programs by calling gcc or g++ in your makefile to do all the compilation and linking steps, allowing you to do all these steps with one simple command. It is not a replacement for the compiler.
'gcc' is the compiler - the program that actually turns the source code into an executable. You have to tell it where the source code is, what to output, and various other things like libraries and options.
'make' is more like a scripting language for compiling programs. It's a way to hide all the details of compiling your source (all those arguments you have to pass the compiler). You script all of the above details once in the Makefile, so you don't have to type it every time for every file. It will also do nifty things like only recompile source files that have been updated, and handle dependancies (if I recompile this file, I will then need to recompile THAT file.)
The biggest difference is that make is turing complete (Are makefiles Turing complete?) while gcc is not.
Let's take the gcc compiler for example.
It only knows how to compile the given .cpp file into .o file given the files needed for compilation to succeed (i.e. dependencies such as .h files).
However, those dependencies create a graph. e.g., b.o might require a.o in the compilation process which means it needs to be compiled independently beforehand.
Do you, as a programer want to keep track of all those dependencies and run them in order for your target .o file to build?
Of course not. You want something to do that task for you.
Those are build tools - tools that help making the build process (i.e. building the artifacts like .o files) easier. One such tool is make.
I hope that clarifies the difference :)