Compile Makefile on Win8/Ubuntu behaves differentl

2019-08-30 14:28发布

问题:

I got a C-Code, written in some Linux Derivation which I wanted to port into Windows. I made some alterations to the Makefile and used mingw32-make to compile them. The produced executive file worked fine until I saw the result.
The program is used to make some data-analysis and should result in a List of numbers between 20 and 100. For an example Data, there should be 3 Numbers around 48.442 .
However, when I run the Windows-executable I get 3 Numbers around 292136359165898530000000000000000000000000000.000

Then I installed virtualbox and tried to run the original Makefile using "make" as console-command, but it complains, that the math-libary isn't requested (pow undefined etc.), although the -lm is inserted on every gcc command.

The windows Makefile:

COMPILER_OPT = -O3

all: extract_timestamps

extract_timestamps: extract_timestamps.c collection.o filename_treatment.o basic_analysis.o  read_lecroy_file.o read_tek_file.o stamp_handling.o treat_lecroy_file.o treat_tek_file.o save_timestamps.o injection_statistics.o calc_time_stamp.o peak_finding.o get_timestamps.o time_ext.h -lm
    gcc -lm -o extract_timestamps.exe basic_analysis.c calc_time_stamp.c collection.c extract_timestamps.c filename_treatment.c get_timestamps.c injection_statistics.c peak_finding.c read_lecroy_file.c read_tek_file.c save_timestamps.c stamp_handling.c treat_lecroy_file.c treat_tek_file.c  $(COMPILER_OPT) 


get_timestamps.o: get_timestamps.c time_ext.h
    gcc $(COMPILER_OPT) -c get_timestamps.c -lm

peak_finding.o: peak_finding.c time_ext.h
    gcc $(COMPILER_OPT) -c -o peak_finding.o peak_finding.c -lm

calc_time_stamp.o: calc_time_stamp.c time_ext.h
    gcc $(COMPILER_OPT) -c -o calc_time_stamp.o calc_time_stamp.c -lm

injection_statistics.o: injection_statistics.c time_ext.h
    gcc $(COMPILER_OPT) -c -o injection_statistics.o injection_statistics.c -lm

save_timestamps.o: save_timestamps.c time_ext.h
    gcc $(COMPILER_OPT) -c -o save_timestamps.o save_timestamps.c -lm

filename_treatment.o: filename_treatment.c time_ext.h
    gcc $(COMPILER_OPT) -c -o filename_treatment.o filename_treatment.c -lm

basic_analysis.o: basic_analysis.c time_ext.h
    gcc $(COMPILER_OPT) -c -o basic_analysis.o basic_analysis.c -lm

collection.o: collection.c time_ext.h
    gcc $(COMPILER_OPT) -c -o collection.o collection.c -lm

read_lecroy_file.o: read_lecroy_file.c time_ext.h
    gcc $(COMPILER_OPT) -c -o read_lecroy_file.o read_lecroy_file.c -lm

read_tek_file.o: read_tek_file.c time_ext.h
    gcc $(COMPILER_OPT) -c -o read_tek_file.o read_tek_file.c -lm

stamp_handling.o: stamp_handling.c time_ext.h
    gcc $(COMPILER_OPT) -c -o stamp_handling.o stamp_handling.c -lm

treat_lecroy_file.o: treat_lecroy_file.c time_ext.h
    gcc $(COMPILER_OPT) -c -o treat_lecroy_file.o treat_lecroy_file.c -lm

treat_tek_file.o: treat_tek_file.c time_ext.h
    gcc $(COMPILER_OPT) -c -o treat_tek_file.o treat_tek_file.c -lm

clean:
    delete filename_treatment.o basic_analysis.o collection.o read_lecroy_file.o stamp_handling.o treat_lecroy_file.o save_timestamps.o injection_statistics.o calc_time_stamp.o peak_finding.o extract_timestamps read_tek_file.o treat_tek_file.o

The ubuntu Makefile:

COMPILER_OPT = -O3

all: extract_timestamps

extract_timestamps: extract_timestamps.c filename_treatment.o basic_analysis.o collection.o \
            read_lecroy_file.o read_tek_file.o stamp_handling.o treat_lecroy_file.o \
            treat_tek_file.o save_timestamps.o injection_statistics.o calc_time_stamp.o \
            peak_finding.o get_timestamps.o time_ext.h
    gcc $(COMPILER_OPT) -o extract_timestamps extract_timestamps.c filename_treatment.o \
                   basic_analysis.o collection.o read_lecroy_file.o read_tek_file.o stamp_handling.o \
                       treat_lecroy_file.o treat_tek_file.o save_timestamps.o injection_statistics.o \
               calc_time_stamp.o peak_finding.o get_timestamps.o; chmod go+rx extract_timestamps -lm


get_timestamps.o: get_timestamps.c time_ext.h
    gcc $(COMPILER_OPT) -c get_timestamps.c -lm

peak_finding.o: peak_finding.c time_ext.h
    gcc $(COMPILER_OPT) -c -o peak_finding.o peak_finding.c -lm

calc_time_stamp.o: calc_time_stamp.c time_ext.h
    gcc $(COMPILER_OPT) -c -o calc_time_stamp.o calc_time_stamp.c -lm

injection_statistics.o: injection_statistics.c time_ext.h
    gcc $(COMPILER_OPT) -c -o injection_statistics.o injection_statistics.c -lm

save_timestamps.o: save_timestamps.c time_ext.h
    gcc $(COMPILER_OPT) -c -o save_timestamps.o save_timestamps.c -lm

filename_treatment.o: filename_treatment.c time_ext.h
    gcc $(COMPILER_OPT) -c -o filename_treatment.o filename_treatment.c -lm

basic_analysis.o: basic_analysis.c time_ext.h
    gcc $(COMPILER_OPT) -c -o basic_analysis.o basic_analysis.c -lm

collection.o: collection.c time_ext.h
    gcc $(COMPILER_OPT) -c -o collection.o collection.c -lm

read_lecroy_file.o: read_lecroy_file.c time_ext.h
    gcc $(COMPILER_OPT) -c -o read_lecroy_file.o read_lecroy_file.c -lm

read_tek_file.o: read_tek_file.c time_ext.h
    gcc $(COMPILER_OPT) -c -o read_tek_file.o read_tek_file.c -lm

stamp_handling.o: stamp_handling.c time_ext.h
    gcc $(COMPILER_OPT) -c -o stamp_handling.o stamp_handling.c -lm

treat_lecroy_file.o: treat_lecroy_file.c time_ext.h
    gcc $(COMPILER_OPT) -c -o treat_lecroy_file.o treat_lecroy_file.c -lm

treat_tek_file.o: treat_tek_file.c time_ext.h
    gcc $(COMPILER_OPT) -c -o treat_tek_file.o treat_tek_file.c -lm

clean:
    rm filename_treatment.o basic_analysis.o collection.o \
           read_lecroy_file.o stamp_handling.o treat_lecroy_file.o save_timestamps.o \
       injection_statistics.o calc_time_stamp.o peak_finding.o \
       read_tek_file.o treat_tek_file.o \

Commandline-commands are "mingw32-make.exe" and "make" without parameters and inside the directory.

I have to say, I usually don't compile directly like that.
Usually I let myself be comforted by some GUI that has working default settings to compile something right. That's probably why I miss something basic here.

Can you please tell me why the windows-executable is treating numbers wrong and why I fail to compile within ubuntu?

Edit:
Here is the main C-code:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include "time_ext.h"

#define DEBUG
//#undef DEBUG

typedef struct{
  char Inputfile[64];
  char Outputfile[64];
  double Fraction;
  int Shift;
  double Threshold;
  int timing;
  int TekwithCapHeader;    /* 1=tektronix with capital header letter,0=LeCroy */
  int TekwithSmallHeader;  /* 1=tektronix with small header letter,0=LeCroy */
}gParameters;



gParameters gParms={
  "infile.dat",
  "outfile.times",
  0.5,                /* fraction */
  8,                  /* shift */
 -8.0,                /* threshold in volts */
  2,                  /* timing method; 1=extrapolation to zero, 2=cfd,3=single threshold*/
  0,                  /* type of the scope with a Capital header*/
  0                   /* type of the scope with a small header*/
};


main(int argc, char **argv){
  int subroutine_return_value;
  FILE *listfp,*outfp,*logfp;
  char lecroyfilename[256],logfilename[256];
  char tekfilename[256], tekheaderfilename[256];    
  /*  int events=0,file_nr=0,shot=0,total_events=0; */
  void *extr_parameters;
  sTraceLimits limits;
  int shot_number=0;
  int number_of_shots;
  int number_of_signals_in_shot, number_of_signals_total;

  // int treat_lecroy_files(char *, FILE *, void *, FILE *,int, int *); /* might change */

  uExtractedParameter get_extraction_parameter(void *, int, int);
  void *parameter_collection(gParameters);


  /* start code */


  /* initialize some things */
  if(getArgs(argc,argv)!=0){
    printf(" !! invalid arguments.....\n      ...... bye!\n");exit(-3);}
  sprintf(logfilename,"%s.log",gParms.Outputfile);
  if((listfp=fopen(gParms.Inputfile,"r"))==NULL){
    fprintf(stderr," !! ERROR: can't open main-inputfile %s, terminating...\n",gParms.Inputfile);exit(-1);}
  if((outfp=fopen(gParms.Outputfile,"w"))==NULL){
    fprintf(stderr," !! ERROR: can't open outputfile %s, terminating...\n",gParms.Outputfile);exit(-1);}
  if((logfp=fopen(logfilename,"w"))==NULL){
    fprintf(stderr," !! ERROR: can't open logfile %s, terminating...\n",logfilename);exit(-1);}
  fprintf(logfp,"logfile to outputfile %s created from inputfile %s\n"
            "user-changeable settings:\n"
            "shift = %d bins\tfraction = %le\tthreshold=%le V\n"\
            "timing method=%2d\n"
            "report on single files to follow\n\n",
      gParms.Outputfile,gParms.Inputfile,
      gParms.Shift,gParms.Fraction,gParms.Threshold,gParms.timing); 
  extr_parameters=parameter_collection(gParms);
  limits.limits_active=LIMITS_INACTIVE;

/*** if switch -X  or -x  ****/

  if((gParms.TekwithCapHeader ==1)||(gParms.TekwithSmallHeader ==1))
  {
  /* treat the Tektronix file */
    while(!feof(listfp)){
      fgets(tekfilename,256,listfp);
      if(feof(listfp)) continue;
      if(tekfilename[strlen(tekfilename)-1]=='\n')
        tekfilename[strlen(tekfilename)-1]='\0';

#ifdef DEBUG
    printf("  *starting treating file %s\n",tekfilename);
#endif  

      subroutine_return_value=treat_tek_file(tekfilename, tekheaderfilename, 
                              outfp,extr_parameters,logfp,limits,
                              shot_number, &number_of_signals_in_shot, &number_of_shots);    


    /* does everything, or should do so at least ;-) */
    /* but now handle the return_value !!! */

    /* next sum the statistics, once it is returned by treat_lecroy_file */

      if(number_of_signals_in_shot>0){
        shot_number += number_of_shots;
        number_of_signals_total+=number_of_signals_in_shot;
      }
    }
  }
  else
  {

  /* treat LeCroy file */
    while(!feof(listfp)){
      fgets(lecroyfilename,256,listfp);
      if(feof(listfp)) continue;
      if(lecroyfilename[strlen(lecroyfilename)-1]=='\n')
        lecroyfilename[strlen(lecroyfilename)-1]='\0';

#ifdef DEBUG
    printf("  *start treating file %s\n",lecroyfilename);
#endif
    subroutine_return_value=treat_lecroy_file(lecroyfilename,outfp,extr_parameters,logfp,limits,
                                              shot_number, &number_of_signals_in_shot);
    /* does everything, or should do so at least ;-) */
    /* but now handle the return_value !!! */

    /* next sum the statistics, once it is returned by treat_lecroy_file */
      if(number_of_signals_in_shot>0){
        shot_number++;
        number_of_signals_total+=number_of_signals_in_shot;
      }

    }


  }
  fclose(outfp);
  fclose(logfp);
  printf("\n");
}






/* **********************************8 subroutines ****************************************8 */




int getArgs(int argc,char **argv)
{  char opt;
   int back=0; 

   int usage(char *);

   if(argc==1) usage(argv[0]);

//   while ((opt = (char)getopt(argc,argv,"hi:o:f:g:b:p:c:t:u:s:xX")) !=EOF)
   while ((opt = (char)getopt(argc,argv,"hi:o:t:f:b:e:xX")) !=EOF)
   {
      switch(opt)
      {
      case 'h': usage(argv[0]); break;
      case 'i': strcpy(gParms.Inputfile,optarg); break;
      case 'o': strcpy(gParms.Outputfile,optarg); break;
      case 't': gParms.Threshold=-fabs((double)atof(optarg)); break;
      case 'f': gParms.Fraction=(double)atof(optarg); break;
      case 'b': gParms.Shift=atoi(optarg); break;
      case 'e': gParms.timing=atoi(optarg); break;
      case 'x': gParms.TekwithSmallHeader=1; break;
      case 'X': gParms.TekwithCapHeader=1; break;
    /*      case 'f': gParms.Minimum_efficiency=(double)atof(optarg); break; */
      case '?': back=-1; break; /* to return error */
      }
   }
   return(back);
}


int usage(char *programm)
{  fprintf(stderr,
           "\n usage: %s  \n\n"
           "        -h             usage\n"
           "        -i [filename] inputfile             Def: infile.dat\n"
           "        -o [filename] outputfile            Def: outfile.times\n"
           "        -t [double]   Threshold             Def:  -8.  V   \n"
           "        -f [double]   Fraction              Def:  0.5    \n"
           "        -b [int]      Shift in bin          Def:  4  \n"
           "        -e [int]      Timestamps extraction Def:  1 \n"
           "        -x,X          for Tektronix format  \n\n"
       "  inputfile is one file containing a list of LeCroy or Tektornix Datafiles\n"
       "  outputfile contains timestamps in ns, shots separated by blank line\n"
       "  in addition a log-file (outputfile.log) is created\n"
       "  options t is the threshold, in fact threshold*sigma(of noise) is the threshold\n"
           "  For tektronix data (high sampling rate >= 20Gs/s):  \n"
           "      -t: threshod, actual threshold is: threshold*sigma \n"
           "      -e: timing method. 1=extraploation to zero (by linear fit), 2=cfd (by linear fit).\n"
           "      -X, -x respectively correspond to *.WFD and *.wfd(header file),however, in my case  \n" 
           "      this does not matter, and the present version can deal with the header automatically \n"
           "  For LeCroy data (low sampling rate < 20 Gs/s): \n"
           "      -t: threshod, actual threshold is: threshold*sigma \n"
           "      -f: fraction,  \n"
           "      -b: shift in bin, \n"
           "      time stamp discriminator: normal cfd, \n"           
       "  Last modified 2008.10 Baohua Sun \n\n",
           programm);
   exit(-1);
}


Makefile see above Output Linux:

gcc -Wall -g -o extract_timestamps extract_timestamps.c filename_treatment.o \
                   basic_analysis.o collection.o read_lecroy_file.o read_tek_file.o stamp_handling.o \
                       treat_lecroy_file.o treat_tek_file.o save_timestamps.o injection_statistics.o \
               calc_time_stamp.o peak_finding.o get_timestamps.o; chmod go+rx extract_timestamps -lm
extract_timestamps.c:37:1: Warnung: Rückgabetyp ist auf »int« voreingestellt [-Wreturn-type]
extract_timestamps.c: In Funktion »main«:
extract_timestamps.c:59:3: Warnung: Implizite Deklaration der Funktion »getArgs« [-Wimplicit-function-declaration]
extract_timestamps.c:93:7: Warnung: Implizite Deklaration der Funktion »treat_tek_file« [-Wimplicit-function-declaration]
extract_timestamps.c:122:5: Warnung: Implizite Deklaration der Funktion »treat_lecroy_file« [-Wimplicit-function-declaration]
extract_timestamps.c:38:7: Warnung: Variable »subroutine_return_value« gesetzt, aber nicht verwendet [-Wunused-but-set-variable]
extract_timestamps.c:140:1: Warnung: Kontrollfluss erreicht Ende von Nicht-void-Funktion [-Wreturn-type]
basic_analysis.o: In function `get_baseline':
basic_analysis.c:(.text+0x7b): undefined reference to `pow'
basic_analysis.c:(.text+0x216): undefined reference to `sqrt'
basic_analysis.c:(.text+0x241): undefined reference to `pow'
basic_analysis.c:(.text+0x263): undefined reference to `sqrt'
basic_analysis.o: In function `get_tek_baseline':
basic_analysis.c:(.text+0x2fb): undefined reference to `pow'
basic_analysis.c:(.text+0x496): undefined reference to `sqrt'
basic_analysis.c:(.text+0x4c1): undefined reference to `pow'
basic_analysis.c:(.text+0x4e3): undefined reference to `sqrt'
read_tek_file.o: In function `read_tek_data':
read_tek_file.c:(.text+0x362): undefined reference to `pow'
calc_time_stamp.o: In function `fitline':
calc_time_stamp.c:(.text+0x165): undefined reference to `sqrt'
calc_time_stamp.o: In function `timestamp_line':
calc_time_stamp.c:(.text+0x323): undefined reference to `sqrt'
calc_time_stamp.c:(.text+0x349): undefined reference to `sqrt'
calc_time_stamp.o: In function `timestamp_parabola1':
calc_time_stamp.c:(.text+0xc28): undefined reference to `sqrt'
calc_time_stamp.o: In function `timestamp_parabola2':
calc_time_stamp.c:(.text+0x1063): undefined reference to `pow'
calc_time_stamp.c:(.text+0x107f): undefined reference to `pow'
calc_time_stamp.c:(.text+0x10f2): undefined reference to `pow'
calc_time_stamp.c:(.text+0x116f): undefined reference to `pow'
calc_time_stamp.c:(.text+0x12a8): undefined reference to `sqrt'
calc_time_stamp.c:(.text+0x12e9): undefined reference to `sqrt'
calc_time_stamp.c:(.text+0x1333): undefined reference to `sqrt'
calc_time_stamp.c:(.text+0x1364): undefined reference to `sqrt'
calc_time_stamp.c:(.text+0x13c5): undefined reference to `sqrt'
calc_time_stamp.o:calc_time_stamp.c:(.text+0x144e): more undefined references to `sqrt' follow
collect2: ld gab 1 als Ende-Status zurück
chmod: Ungültige Option -- l
„chmod --help“ gibt weitere Informationen.
make: *** [extract_timestamps] Fehler 1

Output Windows:

gcc -lm -o extract_timestamps.exe basic_analysis.c calc_time_stamp.c collection.c extract_timestamps.c filename_treatment.c get_timestamps.c injection_statistics.c peak_finding.c read_lecroy_file.c read_tek_file.c save_timestamps.c stamp_handling.c treat_lecroy_file.c treat_tek_file.c  -O3 
filename_treatment.c: In Funktion »separate_filename«:
filename_treatment.c:23:26: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »strrchr« [standardmäßig aktiviert]
filename_treatment.c:25:7: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »strcpy« [standardmäßig aktiviert]
filename_treatment.c:28:11: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »strlen« [standardmäßig aktiviert]
filename_treatment.c:32:5: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »strncpy« [standardmäßig aktiviert]
filename_treatment.c:36:11: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »strlen« [standardmäßig aktiviert]
filename_treatment.c:40:5: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »strncpy« [standardmäßig aktiviert]
filename_treatment.c: In Funktion »make_tek_header_filename«:
filename_treatment.c:73:13: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »strlen« [standardmäßig aktiviert]
filename_treatment.c:75:3: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »strcpy« [standardmäßig aktiviert]
filename_treatment.c:77:20: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »strrchr« [standardmäßig aktiviert]
filename_treatment.c:80:7: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »strcat« [standardmäßig aktiviert]
filename_treatment.c:90:6: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »strcat« [standardmäßig aktiviert]
filename_treatment.c:100:8: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »strcat« [standardmäßig aktiviert]
filename_treatment.c:104:8: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »strcat« [standardmäßig aktiviert]
read_lecroy_file.c: In Funktion »read_lecroy_header«:
read_lecroy_file.c:55:6: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »strlen« [standardmäßig aktiviert]
read_lecroy_file.c:59:3: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »strcpy« [standardmäßig aktiviert]
read_lecroy_file.c:69:3: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »strcat« [standardmäßig aktiviert]
read_lecroy_file.c:134:8: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »strncpy« [standardmäßig aktiviert]
read_lecroy_file.c: In Funktion »read_lecroy_data«:
read_lecroy_file.c:153:3: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »strcpy« [standardmäßig aktiviert]
read_lecroy_file.c:154:3: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »strcat« [standardmäßig aktiviert]
read_tek_file.c: In Funktion »read_tek_header«:
read_tek_file.c:67:7: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »strcpy« [standardmäßig aktiviert]
read_tek_file.c:70:11: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »strcat« [standardmäßig aktiviert]
read_tek_file.c:73:7: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »strcat« [standardmäßig aktiviert]

EDIT: The problem for executing windows/linux executable was that I used windows to make a list of files as input-file. THe program got a simple list of filenames to search through. However, C don't like the \r\n, but only \n, so it got on random somwhere a tailing \r on numbers and filenames. The Windows makefile is working and the linux-makefile was outdated and has the wrong order of files etc.

回答1:

Your Linux Makefile is wrong (it passes -lm to a chmod command but -lmshould be passed as the last argument to the linking gcc command). Remember that order of program arguments to gcc matters a lot.

You don't really need a chmod command, and if you did it should be on a separate line of your Makefile

You should run make -p once to understand what are the builtin rules known by make.

Try something like

 CC= gcc
 CFLAGS= -g -Wall
 LDLIBS= -lm
 SOURCES=  extract_timestamps.c filename_treatment.c basic_analysis.c \
           collection.c read_lecroy_file.c read_tek_file.c \
           stamp_handling.c treat_lecroy_file.c treat_tek_file.c \
           save_timestamps.c injection_statistics.c calc_time_stamp.c \
                    peak_finding.c get_timestamps.c
 OBJECTS= $(patsubst %.c, %.o, $(SOURCES))
 .PHONY: all clean

 all: extract_timestamps

 extract_timestamps: $(OBJECTS)
      $(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@

 ## add or autogenerate rules for object files.

Replace multiple spaces above by a single tab character when appropriate.

The above Makefile is still incomplete. You'll need to complete it (and you want a clean target in it). See this example. You might need:

 %.o: %.c time_ext.h

BTW, I don't recommend using a Makefile generator like cmake in your case. Your program is simple enough to be built by a plain Makefile

And compiling thru a GUI is a bad habit (you might try M-x compile in emacs): the GUI tool is running commands to build your program, and it is hiding them to you. So when something gets wrong you become helpless. Become familiar with Linux commands, they are very helpful!

The different behavior between your Windows and your Linux executables (for the same source code) can have a lot of reasons: undefined behavior, different ways of implementing floating point -the implementation is not only processor dependent, but OS dependent-, different x86 calling conventions, different compiler versions. Writing portable code is a difficult art.

Improve your code till you get no warnings and no errors from the compiler (e.g. with gcc -Wall)