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/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/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
/usr/include/c++/4.1.2/tr1/bind_iterate.h:78: 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」:
/usr/local/mysql/lib/mysql/libmysqlclient.a(charset.c.o): In function `get_charset_name':
/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" {」:
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’不是命名空間‘gongyi::std’中的一個類型名
       typedef std::bidirectional_iterator_tag    iterator_category;
               ^
/usr/include/c++/4.8.2/bits/stl_list.h: 在成員函數‘_Tp* gongyi::std::_List_iterator<_tp>::operator->() const’中:
/usr/include/c++/4.8.2/bits/stl_list.h:150:16: 錯誤:‘__addressof’不是‘gongyi::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,致使引入屢次。node

相關文章
相關標籤/搜索