Linux gcc/g++ TipsHere 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. 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". 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 ... 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 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). 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 } 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. 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; 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 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. 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; }; #endifThe 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. Updated March 3rd,2005 |
Programming‎ > ‎