天天看點

C/C++常見gcc編譯連結錯誤解決方法

除非明确說明,本文内容僅針對x86/x86_64的Linux開發環境,有朋友說baidu不到,開個貼記錄一下(加粗字型是關鍵詞):

用“-Wl,-Bstatic”指定連結靜态庫,使用“-Wl,-Bdynamic”指定連結共享庫,使用示例:

-Wl,-Bstatic -lmysqlclient_r -lssl -lcrypto -Wl,-Bdynamic -lrt -Wl,-Bdynamic -pthread -Wl,-Bstatic -lgtest

("-Wl"表示是傳遞給連結器ld的參數,而不是編譯器gcc/g++的參數。)

1) 下面是因為沒有指定連結參數-lz(/usr/lib/libz.so,/usr/lib/libz.a )

/usr/local/mysql/lib/mysql/libmysqlclient.a(my_compress.c.o): In function `my_uncompress':

/home/software/mysql-5.5.24/mysys/my_compress.c:122: undefined reference to `uncompress'

/usr/local/mysql/lib/mysql/libmysqlclient.a(my_compress.c.o): In function `my_compress_alloc':

/home/software/mysql-5.5.24/mysys/my_compress.c:71: undefined reference to `compress'

2) 下面是因為沒有指定編譯連結參數-pthread(注意不僅僅是-lpthraed)

/usr/local/mysql/lib/mysql/libmysqlclient.a(charset.c.o): In function `get_charset_name':

/home/zhangsan/mysql-5.5.24/mysys/charset.c:533: undefined reference to `pthread_once'

3) 下面這個是因為沒有指定連結參數-lrt

/usr/local/thirdparty/curl/lib/libcurl.a(libcurl_la-timeval.o): In function `curlx_tvnow':

timeval.c:(.text+0xe9): undefined reference to `clock_gettime'

4) 下面這個是因為沒有指定連結參數-ldl

/usr/local/thirdparty/openssl/lib/libcrypto.a(dso_dlfcn.o): In function `dlfcn_globallookup':

dso_dlfcn.c:(.text+0x4c): undefined reference to `dlopen'

dso_dlfcn.c:(.text+0x62): undefined reference to `dlsym'

dso_dlfcn.c:(.text+0x6c): undefined reference to `dlclose'

5) 下面這個是因為指定了連結參數-static,它的存在,要求連結的必須是靜态庫,而不能是共享庫

ld: attempted static link of dynamic object

如果是以-L加-l方式指定,則目錄下必須有.a檔案存在,否則會報-l的庫檔案找不到:ld: cannot find -lACE

6) GCC編譯遇到如下的錯誤,可能是因為在編譯時沒有指定-fPIC,記住:-fPIC即是編譯參數,也是連結參數

relocation R_x86_64_32S against `vtable for CMyClass` can not be used when making a shared object

7) 下面的錯誤表示gcc編譯時需要定義宏__STDC_FORMAT_MACROS,并且必須包含頭檔案inttypes.h

test.cpp:35: error: expected `)' before 'PRIu64'

8) 下面是因為在x86機器(32位)上編譯沒有指定編譯參數-march=pentium4

../../src/common/libmooon.a(logger.o): In function `atomic_dec_and_test':

../../include/mooon/sys/atomic_gcc.h:103: undefined reference to `__sync_sub_and_fetch_4'

9) 下列錯誤可能是因為多了個“}”

error: expected declaration before '}' token

10) 下列錯誤可能是因為少了個“}”

error: expected `}' at end of input

11) 下面這個錯誤是編譯一個共享庫時,該共享庫依賴的一靜态庫編譯時沒有加“-fPIC”參數,解決方法為帶“-fPIC”重新編譯被依賴的靜态庫

relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object; recompile with -fPIC

12) 下面這個錯誤,是因為頭檔案中使用“_syscall0(pid_t, gettid)”不當引起的

./test.o: In function `gettid()':

./test.h:17: multiple definition of `gettid()'

正确的用法是使用"inline"或"static inline"修飾一下:

inline _syscall0(pid_t, gettid)

static inline _syscall0(pid_t, gettid)

當然也可以這樣:

在.h頭檔案中:extern "C" pid_t gettid(void);

在.cpp檔案中:_syscall0(pid_t, gettid)

_syscall0是一個宏,定義一個函數的實作。

13) 下列編譯告警是因為一個static類型的函數未被使用

my.cpp:364: warning: 'int my_function(const cgicc::Cgicc&, const std::string&)' defined but not used

隻需使用“__attribute__((unused))”修飾函數的聲明即可:

static int __attribute__((unused)) my_function(const cgicc::Cgicc&, const std::string&);

14) 執行thrift的configure時遇到如下的錯誤(thrift-0.9.0和thrift-0.9.1遇到過):

checking for setsockopt in -lsocket... no

checking for BN_init in -lcrypto... no

configure: error: "Error: libcrypto required."

原因可能是因為編譯安裝openssl時指定了--prefix,比如--prefix=/usr/local/thirdparty/openssl,可這樣解決:

不指定thrift的configure的--with-openssl=/usr/local/thirdparty/openssl,改為:

CPPFLAGS="-I/usr/local/thirdparty/openssl/include" LDFLAGS="-ldl -L/usr/local/thirdparty/openssl/lib"

替代它就OK了。

15) 下面這個編譯錯誤(表現為g++進入死循環),可能是由于缺少右大括号“}”導緻的,比如定義名字空間時少了“}”:

/usr/include/c++/4.1.2/tr1/type_traits:408: error: 'size_t' is not a member of 'db_proxy::std'

/usr/include/c++/4.1.2/tr1/mu_iterate.h:49: error: 'std::tr1' has not been declared

/usr/include/c++/4.1.2/tr1/bind_iterate.h:78: error: 'std::tr1' has not been declared

16) protoc編譯錯誤,下面錯誤是因為沒有在.proto檔案所在目錄下執行:

/tmp/test.proto: File does not reside within any path specified using --proto_path (or -I).  You must specify a --proto_path which encompasses this file.  Note that the proto_path must be an exact prefix of the .proto file names -- protoc is too dumb to figure out when two paths (e.g. absolute and relative) are equivalent (it's harder than you think).

解決辦法有兩個:一是在.proto檔案所在目錄下執行protoc,二是為protoc指定參數--proto_path,參數值為.proto檔案所在目錄。

17) 下面這個編譯錯誤,可能是因為在全局域内調用一個類對象的成員函數,全局域内是不能直接執行函的:

error: expected constructor, destructor, or type conversion before '->' token

18) 下面這個錯誤是因為沒有連結OpenSSL的libcrypto庫,或者使用了靜态庫,而順序不對:

undefined symbol: EVP_enc_null

19) 下列是連結錯誤,不是編譯錯誤,加上“-pthread”即可,注意不是“-lpthread”:

/home/software/mysql-5.5.24/mysys/charset.c:533: undefined reference to `pthread_once'

/usr/local/mysql/lib/mysql/libmysqlclient.a(charset.c.o): In function `get_charset_number':

20) 依賴OpenSSL(假設安裝在/usr/local/thirdparty/openssl-1.0.2a)時,如果

./configure --prefix=/usr/local/thirdparty/libssh2-1.6.0 --with-libssl-prefix=/usr/local/thirdparty/openssl-1.0.2a

時遇到如下錯誤:

configure: error: No crypto library found!

Try --with-libssl-prefix=PATH

 or --with-libgcrypt-prefix=PATH

 or --with-wincng on Windows

可以如下方法解決:

./configure --prefix=/usr/local/thirdparty/libssh2-1.6.0 --with-openssl CPPFLAGS="-I/usr/local/thirdparty/openssl-1.0.2a/include" LDFLAGS="-L/usr/local/thirdparty/openssl-1.0.2a/lib"

21) 錯誤“error: expected primary-expression before ‘;’ token”可能是因為如下原因:

UserInfoInternal* user_info_internal = new UserInfoInternal;

delete user_info; // 這裡應當是user_info_internal

22) 下面這個編譯錯誤的原因是定義字元串宏時沒有加雙引引号:

example.cpp:563:16: error: too many decimal points in number

如定義成了:#define IP1 127.0.0.1,改成#define IP1 "127.0.0.1"後問題即解決。

23) 下面這個編譯錯誤是因為g++指令參數沒寫對,多了個“-”

g++: -E or -x required when input is from standard input

如:

CPPFLAGS=-pthread -

g++ -g -o $@ $^ $(CPPFLAGS) $(LDFLAGS)

24) libjson_7.6.1編譯錯誤:

makefile:180: Extraneous text after `else' directive

makefile:183: *** only one `else' per conditional.  Stop.

解決辦法:

找到makefile檔案的第180行,将“else ifeq ($(BUILD_TYPE), debug)”,改成兩行内嵌方式:

# BUILD_TYPE specific settings

ifeq ($(BUILD_TYPE), small)

    CXXFLAGS     = $(cxxflags_small)

else

    ifeq ($(BUILD_TYPE), debug) # 不能和else同一行,否則Makefile文法錯誤,不支援else ifeq

        CXXFLAGS     = $(cxxflags_debug)

        libname     := $(libname_debug)

    else

        CXXFLAGS    ?= $(cxxflags_default)

    endif

endif

可以通過設定環境變量來設定BUILD_TYPE,如:export BUILD_TYPE=debug

也可以通過環境變量來設定make install時的安裝目錄,如:export prefix=/usr/local/libjson

相關小知識:

在Makefile檔案中,prefix=/usr和prefix?=/usr,是有差別的,前者指派不能通過環境變量覆寫,後者則可以使用環境變量的值覆寫。

另外,請将第271行删除:

cp -rv $(srcdir)/Dependencies/ $(include_path)/$(libname_hdr)/$(srcdir)

改成:

cp -rv _internal/Dependencies/ $(include_path)/$(libname_hdr)/$(srcdir)

還有第258行前插入如一條指令:

mkdir -p $(inst_path)

否則“cp -f ./$(lib_target) $(inst_path)”,lib将成庫檔案名。

25) 編譯gcc時,如果遇到下面這個錯誤,這是因為運作時找不到mpc、mpfr和gmp的so檔案:

checking for x86_64-unknown-linux-gnu-nm... /data/gcc-4.8.2_src/host-x86_64-unknown-linux-gnu/gcc/nm

checking for x86_64-unknown-linux-gnu-ranlib... ranlib

checking for x86_64-unknown-linux-gnu-strip... strip

checking whether ln -s works... yes

checking for x86_64-unknown-linux-gnu-gcc... /data/gcc-4.8.2_src/host-x86_64-unknown-linux-gnu/gcc/xgcc -B/data/gcc-4.8.2_src/host-x86_64-unknown-linux-gnu/gcc/ -B/data/gcc-4.8.2/x86_64-unknown-linux-gnu/bin/ -B/data/gcc-4.8.2/x86_64-unknown-linux-gnu/lib/ -isystem /data/gcc-4.8.2/x86_64-unknown-linux-gnu/include -isystem /data/gcc-4.8.2/x86_64-unknown-linux-gnu/sys-include   

checking for suffix of object files... configure: error: in `/data/gcc-4.8.2_src/x86_64-unknown-linux-gnu/libgcc':

configure: error: cannot compute suffix of object files: cannot compile

See `config.log' for more details.

make[2]: *** [configure-stage1-target-libgcc] 錯誤 1

是以隻需要如下操作下即可:

export LD_LIBRARY_PATH=/usr/local/mpc/lib:/usr/local/mpfr/lib:/usr/local/gmp/lib:$LD_LIBRARY_PATH

注:gcc-4.8.2依賴mpc、mpfr和gmp:

./configure --prefix=/usr/local/gcc-4.8.2 --with-mpc=/usr/local/mpc-1.0.3 --with-mpfr=/usr/local/mpfr-3.1.3 --with-gmp=/usr/local/gmp-6.0.0

而mpc又依賴于:mpfr和gmp:

./configure --prefix=/usr/local/mpc-1.0.3 --with-mpfr=/usr/local/mpfr-3.1.3 --with-gmp=/usr/local/gmp-6.0.0

26) 編譯gcc時,如果遇到下面這個錯誤:

fatal error: gnu/stubs-32.h: No such file or directory

這是因為在x86_64上,預設會編譯出32位和64位兩個版本。這樣編譯32位時,需要機器上有32位的libc頭檔案和庫檔案,但一些機器上可能沒有,比如沒有/lib目錄,隻有/lib64目錄,這表示不支援32位的libc。為解決這個問題,可以禁止編譯32位版本,在configure時帶上參數--disable-multilib,或者安裝32位版本的glibc。

27)某次編譯遇到如下這樣一個連結錯誤:

redis_dbi.cpp:224: undefined reference to `sdscatlen(char*, void const*, unsigned long)'

按常理,這個錯誤要麼是沒有指定相應的庫,要麼是靜态庫間的順序問題。

但經過檢查,這兩個原因,而是因為gcc和g++混用原因:

1. 庫libhiredis.a和libhiredis.so是由gcc編譯出來的

2. 而調用它的代碼是由g++編譯的,是以導緻了此問題。

問題的解決辦法有兩個:

1. 修改sdscatlen所在的.h檔案,将代碼使用

#ifdef __cplusplus

extern "C" {

#endif

修飾起來,或者直接使用“extern C”修飾函數sdscatlen。

2. 不修改redis的代碼,在引用sds.h時加上“extern "C" {”:

#include "sds.h"

}

上面兩個辦法均可,當然也可以考慮改用g++編譯redis,不過可能會遇到很多錯誤。

redis對外供外部直接使用的頭檔案hiredis.h已使用了extern "C" {,是以不存在問題,隻有當跳過hiredis.h,去使用一些内部頭檔案時需要注意一下。

28)x.hpp:27: error: expected identifier before string constant

x.hpp:27: error: expected `}' before string constant

x.hpp:27: error: expected unqualified-id before string constant

這個錯誤,可能是存在和枚舉等同名的字元串宏,比如存在下面的宏定義:

enum DBTYPE

{

    UNDEFINE = 0,

    MYSQL_DB = 1,

    ORACLE_DB = 2

};

而另一.h檔案中定義了宏:

#define MYSQL_DB "mysql"

29) 下面這個錯誤是因為類成員函數的聲明和定義的傳回值不相同

test.cpp:201:6: 錯誤:‘bool foo(const string&, const string&, const string&, const string&, const string&, const HBaseRowValue&)’的原型不比對類‘CTest’中的任何一個

 bool CHBaseOper::foo(const std::string& tablename, const std::string& rowkey, const std::string& familyname, const std::string& columnname, const std::string& columnvalue, const HBaseRowValue& row_values)

      ^

In file included from test.cpp:8:0:

test.h:58:6: 錯誤:備選為:int foo(const string&, const string&, const string&, const string&, const string&, const HBaseRowValue&)

  int foo(const std::string& tablename, const std::string& rowkey, const std::string& familyname, const std::string& columnname, const std::string& columnvalue, const HBaseRowValue& row_values);

30)

messenger.cpp:5: error: expected unqualified-id before ':' token

該編譯錯誤原因是:

CMessager:CMessager()

即少了個冒号:

CMessager::CMessager()

31) unable to find a register to spill in class ‘SIREG’

編譯時如果遇到這個錯誤,表示遇到一個gcc的bug,最簡單的辦法是去掉編譯參數中的-O3等優化項,然後再試可能就成功了,也可以考慮指定-fno-schedule-insns。

32)像下面這樣一大堆亂七八糟的錯誤,可以考慮是否為少了“}”等引起的

/usr/include/c++/4.8.2/bits/stl_list.h:131:15: 錯誤:‘bidirectional_iterator_tag’不是命名空間‘tom::std’中的一個類型名

       typedef std::bidirectional_iterator_tag    iterator_category;

               ^

/usr/include/c++/4.8.2/bits/stl_list.h: 在成員函數‘_Tp* tom::std::_List_iterator<_tp>::operator->() const’中:

/usr/include/c++/4.8.2/bits/stl_list.h:150:16: 錯誤:‘__addressof’不是‘tom::std’的成員

       { return std::__addressof(static_cast<_Node*>(_M_node)->_M_data); } 

比如:

namespace A { namespace B {

    。。。。。。

// 下面少了一個“}”

} // namespace A { namespace B {

33)crc32’ cannot be used as a function

uint32_t crc32 = crc32(0L, (const unsigned char*)crc32_str.data(), crc32_str.size());

錯誤是因為函數名和變量名相同了,可以改成如下解決:

uint32_t crc32 = ::crc32(0L, (const unsigned char*)crc32_str.data(), crc32_str.size());

34) 

/data/X/mooon/tools/hbase_stress.cpp: In function 'void test_write(const std::map<std::basic_string<char>, std::basic_string<char> >&)':

/data/X/mooon/tools/hbase_stress.cpp:78:117: error: invalid conversion from 'void (*)(uint8_t, const string&, uint16_t) {aka void (*)(unsigned char, const std::basic_string<char>&, short unsigned int)}' to 'mooon::sys::FunctionWith3Parameter<unsigned char, std::basic_string<char>, short unsigned int>::FunctionPtr {aka void (*)(unsigned char, std::basic_string<char>, short unsigned int)}' [-fpermissive]

             stress_threads[i] = new mooon::sys::CThreadEngine(mooon::sys::bind(write_thread, i, hbase_ip, hbase_port));                                                                                                                     ^

In file included from /data/X/mooon/tools/hbase_stress.cpp:24:0:

/data/X/mooon/tools/../include/mooon/sys/thread_engine.h:777:16: error:   initializing argument 1 of 'mooon::sys::Functor mooon::sys::bind(typename mooon::sys::FunctionWith3Parameter<Parameter1Type, Parameter2Type, Parameter3Type>::FunctionPtr, Parameter1Type, Parameter2Type, Parameter3Type) [with Parameter1Type = unsigned char; Parameter2Type = std::basic_string<char>; Parameter3Type = short unsigned int; typename mooon::sys::FunctionWith3Parameter<Parameter1Type, Parameter2Type, Parameter3Type>::FunctionPtr = void (*)(unsigned char, std::basic_string<char>, short unsigned int)]' [-fpermissive]

 inline Functor bind(typename FunctionWith3Parameter<Parameter1Type, Parameter2Type, Parameter3Type>::FunctionPtr function_ptr, Parameter1Type parameter1, Parameter2Type parameter2, Parameter3Type parameter3)

上面這個錯誤的意思是第一個參數的類型為

void (*)(unsigned char, std::basic_string<char>, short unsigned int)

但傳入的類型為

void (*)(unsigned char, const std::basic_string<char>&, short unsigned int)

從上面的對比可以看出,要求函數的第二個參數為std::string類型,而不是const std::string&類型。

35) conflicting declaration

has a previous declaration as

這個錯誤可能是因為頭檔案沒有#ifndef,導緻引入多次。

36) warning: cannot pass objects of non-POD type ‘const struct std::basic_string<char, std::char_traits<char>, std::allocator<char> >’ through ‘...’; call will abort at runtime

warning: format ‘%s’ expects type ‘char*’, but argument 3 has type ‘int

這個錯誤是因為格式化%s參數的值為std::string值,這個在運作時可能會觸發SIGILL(Illegal instruction),例如:

std::string type;

std::string name;

。。。 。。。

const std::string& key = mooon::utils::CStringUtils::format_string("%s_%s", type.c_str(), name);

37)'__curl_rule_01__' is negative

這個編譯錯誤,是因為在64位平台上編譯64位程式,但curl庫是32位方式編譯的。

38)countable_log_writer.cpp:54:50: 錯誤:從類型‘const CCounter*’到類型‘CCounter*’的轉換無效 [-fpermissive]

     return (NULL == counter)? &_default_counter: counter;

                                                  ^

錯誤實際出在_default_counter的使用上,傳回的是非const類型的CCounter*。

而由于函數get_counter是const類型函數,意味着this也是const類型,

&_default_counter也就成了const CCounter*類型。

簡單的修改方法是将_default_counter定義成CCounter*指針類型,而非CCounter對象類型。

CCounter* CCountableLogWriter::get_counter(const std::string& type) const

    CCounter* counter = NULL;

    CCounterTable::const_iterator iter = _counter_table.find(type);

    if (iter != _counter_table.end())

        counter = iter->second;

    return (NULL == counter)? &_default_counter: counter;