Programming‎ > ‎

GCC/G++

Linux gcc/g++ Tips

Here are Linux gcc/g++ programming tips.

Index


How can I mix dynamic and static libraries for an application compilation?

Here is the link part of makefile which does it


  yourapp: $(OBJDIR)/$(OBJS) 
    $(CC) $(LDFLAGS) -o $(EXEDIR)/$@ $^ \      
	-Wl,-Bstatic $(STATICLIBS) \      
	-Wl,-Bdynamic $(DYNAMICLIBS)
  

Make sure that the lines starts with TAB character (Makefile requirement). The option "-Wl," passes the next argument to the linker. That is,"-Bstatic" and "-Bdynamic" are linker options.

Top


How can I see the dependent dynamic libraries for an application?

Microsoft Visual C++ has the utility called dumpbin. On Linux,use ldd, which shows you not only needed dynamic libraries, but also where those dynamic libraries are on that machine. Here is the sample.


  $ ldd plotter        
  libGLU.so.1 => /usr/lib/libGLU.so.1 (0x4002d000)        
  libglut.so.3 => /usr/lib/libglut.so.3 (0x400a9000)        
  libqt-mt.so.3 => /usr/local/qt/lib/libqt-mt.so.3 (0x400db000)        
  libpng.so.2 => /usr/lib/libpng.so.2 (0x40896000)        
  libz.so.1 => /usr/lib/libz.so.1 (0x408b8000)        
  libXext.so.6 => /usr/X11R6/lib/libXext.so.6 (0x408c6000)        
  libX11.so.6 => /usr/X11R6/lib/libX11.so.6 (0x408d3000)        
  ...
  

If you do not have the used dynamic libraries, you will see "not found".

Top


How can I see symbols in the dynamic libraries?

It is usually work by doing nm libname. However, it won't work withNVidia libGL.so.

  
  nm libGL.so  
  nm: libGL.so: no symbols
  

What? I don't understand. It needed -D option. This means that libGL.so has symbols in the initialized data section only.

  
  nm -D libGL.so | more         
  U calloc         
  U close         
  U dlclose         
  U dlopen         
  U dlsym00058a78 a _DYNAMIC         
  ...
  

Top


How can I create a patch file?

When you want to produce a patch file, you create two directories. The first one to be the original source tree and the second one to be your edited tree. Then do

  
  diff -r -c -b -B orig mine > patch.txt
  

In order to apply the patch, go into the orig directory and then do:

  
  cd orig  
  patch -p1 < ../patch.txt
  

Top


How can I debug memory leak?

The common problems of C programs is to keep track of alloc and free.If you are not careful, you may be touching the non-allocated region whichmay cause segmentation faults. The memory problem is subtle so that segmentation may not occur.

The easiest one to use is valgrind (http://valgrind.kde.org).

 
  Requirement: must link with at least one shared library   
  Pros       : no need to modify the source codes nor makefile 
  Cons       : uses three times or more memory.            
             : runs very slow
  

The older version did not support SSE nor NVidia video driver code in the GUI application. The new version supports SSE and runs the GUI application also (libGLcore.so.1.0.5336 from NVidia has many errors).

  
  valgrind --suppression=~/tosa.supp --tool=memcheck --leak-check=yes (progname)
  

You should see the following immediately:


  ==19859== Memcheck, a memory error detector for x86-linux.
  ==19859== Copyright (C) 2002-2004, and GNU GPL'd, by Julian Seward.
  ==19859== Using valgrind-2.1.1, a program supervision framework for x86-linux.
  ==19859== Copyright (C) 2000-2004, and GNU GPL'd, by Julian Seward.
  ==19859== For more details, rerun with: -v
  

If you don't see the lines above, your program is using only static libraries and thus you must change makefile. The --suppression flag tells valgrind to suppress warnings anderrors listed in tosa.supp file. For example, RH9 I/O routines emit many warnings and thus I created the following file. Please go to the valgrind web page and read about how to write a suppression file.


  # 
  # tosa.supp
  # 
  RH9 I/O error suppression
  #
  {  _IO_vfscanf  Memcheck:Cond  fun:_IO_vfscanf  fun:*}
  {  _IO_vfprintf  Memcheck:Cond  fun:_IO_vfprintf  fun:*}
  {  __uflow  Memcheck:Cond  fun:__uflow  fun:*}
  {  __underflow  Memcheck:Cond  fun:__underflow  fun:*}
  {  _IO_fwrite  Memcheck:Cond  fun:_IO_fwrite  fun:*}
  {  _IO_fputs  Memcheck:Cond  fun:_IO_fputs  fun:*}
  

One method is to use dmalloc library (http://dmalloc.com).

The debug memory allocation or dmalloc library has been designed as a drop in replacement for the system's malloc, realloc, calloc, free and other memory management routines while providing powerful debugging facilities configurable at runtime. These facilities include such things as memory-leak tracking, fence-post write detection, file/line number reporting, and general logging of statistics.

The problem I encountered was the line numbers limit artificially introduced in the compilation (10000 lines). In order to deal with bigger C programs, you have to recompile dmalloc by changing the following line in the file settings.dist to something bigger (in my case 40000):

 
  #define MAX_LINE_NUMBER         10000
  

After compilation and installation, you edit your source code to have the following:

  
  #ifdef DMALLOC  
  #include "dmalloc.h"  
  #endif
  

Then link with dmalloc library of appropriate type (static .a or shared lib .so and non-thread or thread version)

  
  C non-thread 
  static  : libdmalloc.a               
  shared  : libdmalloc.so  
  C thread 
  static      : libdmallocth.a           
  shared      : libdmallocth.so  
  C++ non-thread 
  static: libdmallocxx.a                 
  shared: libdmallocxx.so  
  C++ thread 
  static    : libdmallocthcxx.a             
  shared    : libdmallocthcxx.so
  

Then, you add the following in .cshrc or .bashrc:

  
  tcsh or csh:    
  alias dmalloc 'eval `\/usr/pubsw/packages/dmalloc/5.3.0/bin/dmalloc -C \!*`'  
  bash:    
  function dmalloc { eval `command /usr/pubsw/packages/dmalloc/5.3.0/bin/dmalloc -b $*`; }
  

where we installed the dmalloc in /usr/pubsw/packages/dmalloc/5.3.0. You must change it to the right directory. Once you have that, you can do

  
  $ dmalloc --usage
  

Before you run, you set up what to do for dmalloc.

 
  dmalloc -l logfile -i 100 low    
  * set the malloc log path to `logfile' (-l logfile)    
  * have the library check itself every 100 iterations (-i 100)    
  * enable a number of debug features (low). 
  

Top


How can I get the memory usage information by a program?

Linux now uses proc system to list various runtime properties. Detailed explanationcan be found (on RedHat) in e.g. /usr/src/linux-2.4.20-20.9/Documentation/filesystems/proc.txt. You may have the newer version of linux-2.4.x-y.9.

One of them is the current memory usage status per process id. If you look at/proc/$pid/status where $pid is the process id you are interested in,it has the following info:

  
  Name:	netscape-bin  
  State:S (sleeping)  
  Tgid:	1369  
  Pid:	1369  
  PPid:	1363  
  TracerPid:	0  
  Uid:	500	500	500	500  
  Gid:	500	500	500	500  
  FDSize:	256  
  Groups:	500 0   
  VmSize:	  118172 kB  
  VmLck:	       0 kB  
  VmRSS:	   41776 kB  
  VmData:	   88500 kB  
  VmStk:	      68 kB  
  VmExe:	     924 kB  
  VmLib:	   23192 kB  
  SigPnd:	0000000000000000  
  SigBlk:	0000000100000000  
  SigIgn:	8000000000001000  
  SigCgt:	00000000800064ff  
  CapInh:	0000000000000000  
  CapPrm:	0000000000000000  
  CapEff:	0000000000000000
  

where VmRSS: resident memory size, VmData: virtual memory heap used, VmStk: stack size used, VmExe : executable memory usage, VmLib : current dynamiclibrary memory usage. VmSize : the total memory usage. The following routineis a C program to get the VmData (current heap size) value at runtime. See http://www.mozilla.org/projects/footprint/footprint-guide.html


  unsigned int getMemoryUsed()
  { 
    FILE *fp = 0; 
	char buf[256]; 
	unsigned int memused = 0; 
	int numassigned = 0; 
	static int used = 0; 
	sprintf(buf, "grep -i vmdata /proc/%d/status | cut -f 2", getpid()); 
	errno = 0; 
	fp = popen(buf, "r"); 
	if (fp) 
	{   
	  numassigned = fscanf(fp, "%u", &memused);   
	  if (numassigned == 1)   
	  {     
	    pclose(fp);     
		return memused;   
	  }   
	  else // somehow could not do fscanf failed   
	  {     
	    pclose(fp);     
		errno = 0;     
		fprintf(stderr, "getting memoryused failed");     
		return -1;   
	  } 
	} 
	if (errno) 
	{   
	  errno = 0;   
	  fprintf(stderr, "getting memoryused failed");   
	  return -1; 
	} 
	return -1;  // this should never happen
  }
  

Top


Why does a pthread program core dump?

When I tried to run a simple pthread program, it keeps core dumping. Even though pthread_create() return error code, it segfaults before returning info. It turned out that I just needed the compiler flag:

  
  -pthread
  

Without this flag, gcc compiles the program fine, but the executable dumps core.

Top


How can I read/write a gzipped file in a program (using pipe)?

You can execute any program within your program, using pipe. First, do this in a C. When you deal with pipe, you have to consider how to connect pipes between two processes. The most convenient one is popen which return stream pointer FILE * and thus you can use it as if youare dealing with a file. Note that the corresponding Microsoft version is _popen and _wpopen(depending on the command line is const char * or const wchar_t). In either case "stdio.h" is theonly header needed.

   
  // reading part   ///////////////////////////////////////////////////////////////////   
  // declare function pointer so that you can use fclose() or pclose()   
  int (*myclose)(FILE *stream);   
  if (strstr(fname, ".gz"))   
  {     
    char command[512];     
	myclose = pclose;     
	strcpy(command, "zcat ");     
	strcat(command, fname);     
	fp = popen(command, "r");  // Microsoft version may need to be "rb".   
  }   
  else   
  {     
    myclose = fclose;     
	fp =fopen(fname, "rb");   
  }   
  // use fp as usual    
  ...   
  myclose(fp);   
  // writing part   ////////////////////////////////////////////////////////////////////   
  if (strstr(fname, ".gz"))   
  {     
    char command[512];     
	myclose = pclose;     
	strcpy(command, "gzip -f -c > ");     
	strcat(command, fname);     
	fp = popen(command, "w");   // Microsoft version may need to be "wb"   
  }   
  else   
  {     
    myclose = fclose;     
	fp = fopen(fname, "wb");   
  }   
  // use fp as usual   
  ...   
  myclose(fp);
  

In order to do this in C++, you think of stream style. Unfortunately, the standard C++ at this time does not have "pipe" stream. A few people came up with the creation of such stream. Pre-3 gcc had such a support, but it was dropped from gcc3. I got two solutions by googling but both won't work under gcc 2.96 (RedHat 7.3). I was able to minimally modify fdstream.hpp to work under gcc 2.96.

Nicolai Josuttis came up with fdstream http://www.josuttis.com/cppcode/fdstream.html, which is just a simple wrapper and thus popen is explicit and you must close with pclose.

    
  FILE* fp;    
  // open pipe to read from    
  if ((fp=popen(command.c_str(),"r")) == NULL) 
  {        
    throw "popen() failed";    
  }    
  // and initialize input stream to read from it    
  boost::fdistream in(fileno(fp));    
  ...    
  // close pipe    
  pclose(fp);
  

Jonathan Wakely started PStreams as a sourceforge.net project http://sourceforge.net/projects/pstreams. You can find the documentation in http://pstreams.sourceforge.net/doc/index.html. These classes, ipstream, opstream, pstream and associated pstreambuf, do not use popen(), but uses up to three pipes to do the job. Here is an example.

  
  red::ipstream in("ls ./*.h");  
  std::string str;  
  while (in >> str)    
    std::cout << str << std::endl;
  

Top


How can I get the glibc version?

The version of glibc is very important for your application development, since it is the base library. There are few ways to get this major and minor version.


  Method 1:  
  $ iconv --version  
  iconv (GNU libc) 2.3.2  Copyright (C) 2003 Free Software Foundation, Inc.  
  This is free software; see the source for copying conditions.  There is NO  warranty; 
  not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  Written by Ulrich Drepper.  
  Method 2:  
  $ strings /usr/lib/libc.a | grep GNU  
  GNU C Library stable release version 2.3.2, by Roland McGrath et al.  
  Compiled by GNU CC version 3.2.2 20030222 (Red Hat Linux 3.2.2-5).        
  GNU libio by Per Bothner  (RedHat 9 produced this.  SUSE 9 has more GNU C strings around.)
  Method 3: (Thanks to Paul Raines)  
  $ cat /usr/include/features.h | grep GLIBC  
  The macros `__GNU_LIBRARY__', `__GLIBC__', and `__GLIBC_MINOR__' are  on.  
  The use of this variable is deprecated.  
  Use __GLIBC__ and  __GLIBC_MINOR__ now (see below) when you want to test for a specific  
  #define __GLIBC__2  
  #define __GLIBC_MINOR__ 3
  

Top


How can I write C programs using the C++ library which exports C functions?

This was the scenario I encountered. I had to use the C++ library which exports C functions in my C program. When I linked this library, I get many unresolved symbols like __cxa_begin_catch,__cxa_end_catch, etc. After adding link to libstdc++ (-lstdc++), everything resolved when the programis dynamically linked. When I tried to link statically, it did not work. How can I resolve this problem?

Here comes the interesting twist. In the usual lib directory /usr/lib, I cannot find the static version of the libstdc++. I can only find the shared library version. However, I can create a static binary with g++. How can g++ create a static binary?

It turned out that the static library libstdc++.a lives in /usr/lib/gcc-lib/i386-redhat-linux/3.2.2. This place is known to the g++ installed on the system, but not me. How can I use to create a C program linked with a C++ library which exports C functions? The answer is to use g++ as the linker.

Another nice feature of GNU autoconf/automake/libtool framework allows us to do thisvery easily in Makefile.am:

  
  CCLD=g++
  
where usually CCLD=gcc for C programs.

How can I fix the error: /usr/lib/libGL.la is not a valid archive?

Thanks to Scott Newton Kile KDE LaTex Editor mail archive, I was able to solve this problem.

Do you have a NVIDIA graphics card using the latest release of 5328? If you do, you need to change the first two lines:

 
  # libGL.la - a libtool library file 
  # Generated by nvidia-installer: 1.0.5  
  to  
  # libGL.la - a libtool library file 
  # Generated by ltmain.sh - GNU libtool 1.4.3 (1.922.2.110 2002/10/23 01:39:54) 
  # Generated by nvidia-installer: 1.0.5
  

KDE specifically checks for "Generate by ... libtool" so it fails on the second line.

Top


How are NaN and Inf defined in the IEEE754 spec?

IEEE defines the arithmetic model by IEEE Standard for Binary Floating-Point Arithmetic, ANSI/IEEE Std 754-1985 (IEEE 754). allmost all processors use IEEE arithmetic. Here is a SUN site explainingall the details.

The IEEE single format: f: 23 bit fraction, e: 8 bit biased exponent, s: 1 bit sign = 32 bit


  #if __BYTE_ORDER == __BIG_ENDIAN
  union ieee754_float  
  {    
    float f;    
	struct      
	{	
	  unsigned int s:1;	
	  unsigned int e:8;	
	  unsigned int f:23;      
	} 
	ieee;  
  };
  #else // little endian
  union ieee754_float  
  {    
    float f;    
	struct      
	{	
	  unsigned int f:23;	
	  unsigned int e:8;	
	  unsigned int s:1;      
	} 
	ieee;  
  };
  #endif
  
The three abnormal numbers are defined as follows:
    
  +INF (positive infinity) : s = 0, e = 255, f = 0 (all bits are zero)    
  -INF (negative infinity) : s = 1, e = 255, f = 0 (all bits are zero)    
  NaN  (Not a Number)      : s = u, e = 255, f != 0 (at least one bit is not zero)
  
You check these abnormal ones by
    
  union ieee754_float v;    
  v.f = invalue;    
  // check v.s, v.e, v.f
  

The IEEE double format: f: 52 bit , e: 11 bit biased expoent, s: 1 bit sign = 64 bit. The abnormal numbers are defined in the same way as a single precision version.

Top

Home

Updated March 3rd,2005