Make and GCC

From Wiki at Neela Nurseries
Jump to: navigation, search


Overview

This article contains notes about GNU `make` and related tools, for compiling and cross-compiling C programs.


^ GNU Make Quick Reference

Quoting from the manual for quick reference:

    <i>
    "It’s very important that you recognize the limited scope in which automatic variable values are available: they only have values within the recipe. In particular, you cannot use them anywhere within the target list of a rule; they have no value there and will expand to the empty string. Also, they cannot be accessed directly within the prerequisite list of a rule. A common mistake is attempting to use $@ within the prerequisites list; this will not work. However, there is a special feature of GNU make, secondary expansion (see Secondary Expansion), which will allow automatic variable values to be used in prerequisite lists.
    
    Here is a table of automatic variables:
    
    $@
    
        The file name of the target of the rule. If the target is an archive member, then ‘$@’ is the name of the archive file. In a pattern rule that has multiple targets (see Introduction to Pattern Rules), ‘$@’ is the name of whichever target caused the rule’s recipe to be run.
    $%
    
        The target member name, when the target is an archive member. See Archives. For example, if the target is foo.a(bar.o) then ‘$%’ is bar.o and ‘$@’ is foo.a. ‘$%’ is empty when the target is not an archive member.
    $<
    
        The name of the first prerequisite. If the target got its recipe from an implicit rule, this will be the first prerequisite added by the implicit rule (see Implicit Rules).
    $?
    
        The names of all the prerequisites that are newer than the target, with spaces between them. For prerequisites which are archive members, only the named member is used (see Archives).
    $^
    
        The names of all the prerequisites, with spaces between them. For prerequisites which are archive members, only the named member is used (see Archives). A target has only one prerequisite on each other file it depends on, no matter how many times each file is listed as a prerequisite. So if you list a prerequisite more than once for a target, the value of $^ contains just one copy of the name. This list does not contain any of the order-only prerequisites; for those see the ‘$|’ variable, below.
    $+
    
        This is like ‘$^’, but prerequisites listed more than once are duplicated in the order they were listed in the makefile. This is primarily useful for use in linking commands where it is meaningful to repeat library file names in a particular order.
    $|
    
        The names of all the order-only prerequisites, with spaces between them.
    $*
    
        The stem with which an implicit rule matches (see How Patterns Match). If the target is dir/a.foo.b and the target pattern is a.%.b then the stem is dir/foo. The stem is useful for constructing names of related files.
    
        In a static pattern rule, the stem is part of the file name that matched the ‘%’ in the target pattern.
    
        In an explicit rule, there is no stem; so ‘$*’ cannot be determined in that way. Instead, if the target name ends with a recognized suffix (see Old-Fashioned Suffix Rules), ‘$*’ is set to the target name minus the suffix. For example, if the target name is ‘foo.c’, then ‘$*’ is set to ‘foo’, since ‘.c’ is a suffix. GNU make does this bizarre thing only for compatibility with other implementations of make. You should generally avoid using ‘$*’ except in implicit rules or static pattern rules.
    
        If the target name in an explicit rule does not end with a recognized suffix, ‘$*’ is set to the empty string for that rule. 
    
    ‘$?’ is useful even in explicit rules when you wish to operate on only the prerequisites that have changed. For example, suppose that an archive named lib is supposed to contain copies of several object files. This rule copies just the changed object files into the archive: . . ."
    </i>
    


^ C pre-processor


^ Tests of C Macros

Following 2022 Q4 C program written to better understand C macro expansion. Simple C program to observe macro expansion and to unroll error messages:

#include <stdio.h>
#include <stdlib.h>


// Compile with:
//
//    $ gcc -Wall main.c
//
// As of 2022-06-09 Builds with 'gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0'


#define SIZE_OF_64_BYTES (64)

#define NN_CONCAT_2(x,y) x##y
#define NN_PREFIX_WITH_NN_MARKER(x) NN_CONCAT_2(__nn__,x)
#define NN_POSTFIX_WITH_NN_MARKER(x) NN_CONCAT_2(x,__nn__)
#define NN_BOUND_WITH_NN_MARKER(x) NN_PREFIX_WITH_NN_MARKER(NN_POSTFIX_WITH_NN_MARKER(x))

int main(int argc, char *argv[])
{
//    int z = 3;
    char lbuf[SIZE_OF_64_BYTES] = { 0 };
//    char __nn__z__nn__[SIZE_OF_64_BYTES] = { 0 };

    snprintf(lbuf, SIZE_OF_64_BYTES, "%s", NN_BOUND_WITH_NN_MARKER(z));
    printf("%s", lbuf);

    return 0;
}


Compile time error messages, errors intentionally created to understand elements of message:

ted@localhost1:~/projects/c/macros$ gcc -Wall main.c
main.c: In function ‘main’:
main.c:15:49: error: ‘__nn__z__nn__’ undeclared (first use in this function)
   15 | #define NN_PREFIX_WITH_NN_MARKER(x) NN_CONCAT_2(__nn__,x)
      |                                                 ^~~~~~
main.c:14:26: note: in definition of macro ‘NN_CONCAT_2’
   14 | #define NN_CONCAT_2(x,y) x##y
      |                          ^
main.c:17:36: note: in expansion of macro ‘NN_PREFIX_WITH_NN_MARKER’
   17 | #define NN_BOUND_WITH_NN_MARKER(x) NN_PREFIX_WITH_NN_MARKER(NN_POSTFIX_WITH_NN_MARKER(x))
      |                                    ^~~~~~~~~~~~~~~~~~~~~~~~
main.c:25:44: note: in expansion of macro ‘NN_BOUND_WITH_NN_MARKER’
   25 |     snprintf(lbuf, SIZE_OF_64_BYTES, "%s", NN_BOUND_WITH_NN_MARKER(z));
      |              ted@localhost1:~/projects/c/macros$ gcc -Wall main.c
main.c: In function ‘main’:
main.c:15:49: error: ‘__nn__z__nn__’ undeclared (first use in this function)
   15 | #define NN_PREFIX_WITH_NN_MARKER(x) NN_CONCAT_2(__nn__,x)
      |                                                 ^~~~~~
main.c:14:26: note: in definition of macro ‘NN_CONCAT_2’
   14 | #define NN_CONCAT_2(x,y) x##y
      |                          ^
main.c:17:36: note: in expansion of macro ‘NN_PREFIX_WITH_NN_MARKER’
   17 | #define NN_BOUND_WITH_NN_MARKER(x) NN_PREFIX_WITH_NN_MARKER(NN_POSTFIX_WITH_NN_MARKER(x))
      |                                    ^~~~~~~~~~~~~~~~~~~~~~~~
main.c:25:44: note: in expansion of macro ‘NN_BOUND_WITH_NN_MARKER’
   25 |     snprintf(lbuf, SIZE_OF_64_BYTES, "%s", NN_BOUND_WITH_NN_MARKER(z));
      |                                            ^~~~~~~~~~~~~~~~~~~~~~~
main.c:15:49: note: each undeclared identifier is reported only once for each function it appears in
   15 | #define NN_PREFIX_WITH_NN_MARKER(x) NN_CONCAT_2(__nn__,x)
      |                                                 ^~~~~~
main.c:14:26: note: in definition of macro ‘NN_CONCAT_2’
   14 | #define NN_CONCAT_2(x,y) x##y
      |                          ^
main.c:17:36: note: in expansion of macro ‘NN_PREFIX_WITH_NN_MARKER’
   17 | #define NN_BOUND_WITH_NN_MARKER(x) NN_PREFIX_WITH_NN_MARKER(NN_POSTFIX_WITH_NN_MARKER(x))
      |                                    ^~~~~~~~~~~~~~~~~~~~~~~~
main.c:25:44: note: in expansion of macro ‘NN_BOUND_WITH_NN_MARKER’
   25 |     snprintf(lbuf, SIZE_OF_64_BYTES, "%s", NN_BOUND_WITH_NN_MARKER(z));
      |                                            ^~~~~~~~~~~~~~~~~~~~~~~
ted@localhost1:~/projects/c/macros$                              ^~~~~~~~~~~~~~~~~~~~~~~
main.c:15:49: note: each undeclared identifier is reported only once for each function it appears in
   15 | #define NN_PREFIX_WITH_NN_MARKER(x) NN_CONCAT_2(__nn__,x)
      |                                                 ^~~~~~
main.c:14:26: note: in definition of macro ‘NN_CONCAT_2’
   14 | #define NN_CONCAT_2(x,y) x##y
      |                          ^
main.c:17:36: note: in expansion of macro ‘NN_PREFIX_WITH_NN_MARKER’
   17 | #define NN_BOUND_WITH_NN_MARKER(x) NN_PREFIX_WITH_NN_MARKER(NN_POSTFIX_WITH_NN_MARKER(x))
      |                                    ^~~~~~~~~~~~~~~~~~~~~~~~
main.c:25:44: note: in expansion of macro ‘NN_BOUND_WITH_NN_MARKER’
   25 |     snprintf(lbuf, SIZE_OF_64_BYTES, "%s", NN_BOUND_WITH_NN_MARKER(z));
      |                                            ^~~~~~~~~~~~~~~~~~~~~~~
ted@localhost1:~/projects/c/macros$


^ Cmake

Software compilation tool cmake now has a dedicated cmake notes page on this wiki. One early note regarding cmake remains here:


^ The GNU Assembler

While cross-compiling on an i686 host system with an ARM Cortex-M0 target, running into a troublesome word-alignment issue which does not occur in the same project when built under LPCXpresso 8p2p2. There are two issues we observe this July 2018: (1) the word alignment issue and (2) hand-rolled GNU makefile compiling the LPC start-up source file like all others, when this source file's compiler options are noted to be a little different during LPC's build process. Specifically there's one additional option passed to the compiler, which is -Os, an option to direct comipler to optimize output code for size.

Here's a general tutorial style article on-line which discusses how to pass options to an assembler:

Some additional references:


^ GCC Arm Cross Compiler

Following excerpt copied from ARM gcc readme file in /opt/gcc-arm-none-eabi-7-2018/gcc-arm-none-eabi-7-2018-q2-update/readme.txt. This file has explanation of Newlib and Newlib.nano C libraries, and also mentions ARM compiler options for floating point formatting support . . .

    22 For some Ubuntu releases, the toolchain can also be installed via
    23 Launchpad PPA at https://launchpad.net/~team-gcc-arm-embedded/+archive/ubuntu/ppa.

Need to figure out which source / versions of gcc cross compiler are free of bugs which trigger the following warning in ChibiOS library file chcore

129 /* Handling a GCC problem impacting ARMv6-M.*/
130 #if defined(__GNUC__) && !defined(PORT_IGNORE_GCC_VERSION_CHECK)
131 #if ( __GNUC__ > 5 ) && ( __GNUC__ < 10 )
132 #define GCC_VERSION ( __GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ )
133 #if ( __GNUC__ == 7 ) && ( GCC_VERSION >= 70500 )
134 #elif ( __GNUC__ == 8 ) && ( GCC_VERSION >= 80400 )
135 #elif ( __GNUC__ == 9 ) && ( GCC_VERSION >= 90300 )
136 #else
137 #warning "This compiler has a know problem with Cortex-M0, see GCC bugs: 88167, 88656."
138 #endif
139 #endif
140 #endif

ChibiOS lead developer Giovanni discusses this matter in brief here at ChibiOS forum post t=5281:

 *  https://forum.chibios.org/viewtopic.php?t=5281


^ References

- 2018-06-15 Friday -

Some good explanations and introduction regarding how to include library files in C and C++ projects, on Linux, Mac and Windows systems:

- 2018-07-10 Tuesday -


- 2018-07-12 Thursday -


- 2018-12-26 Wednesday -