2026-04-02 23:12:36 +08:00

533 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: 常见gcc编译问题解决方法集
author: 一见
createTime: 2021/09/28
tags:
- gcc
- 转载
categories:
- 随记
---
> 作者:一见
> 参考[https://www.cnblogs.com/aquester/p/9891584.html](https://www.cnblogs.com/aquester/p/9891584.html)
除非明确说明,本文内容仅针对 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`
```text
/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`
```text
/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`
```text
/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`
```text
/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`,它的存在,要求链接的必须是静态库,而不能是共享库
```text
ld: attempted static link of dynamic object
```
如果是以`-L``-l`方式指定,则目录下必须有`.a`文件存在,否则会报`-l`的库文件找不到:`ld: cannot find -lACE`
6. GCC 编译遇到如下的错误,可能是因为在编译时没有指定`-fPIC`,记住:`-fPIC`即是编译参数,也是链接参数
```text
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`
```text
test.cpp:35: error: expected `)' before 'PRIu64'
```
8. 下面是因为在 x86 机器32 位)上编译没有指定编译参数`-march=pentium4`
```text
../../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. 下列错误可能是因为多了个`}`
```text
error: expected declaration before '}' token
```
10. 下列错误可能是因为少了个`}`
```text
error: expected `}' at end of input
```
11. 下面这个错误是编译一个共享库时,该共享库依赖的一静态库编译时没有加`-fPIC`参数,解决方法为带`-fPIC`重新编译被依赖的静态库
```text
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)`不当引起的
```text
./test.o: In function `gettid()':
./test.h:17: multiple definition of `gettid()'
```
正确的用法是使用"inline"或"static inline"修饰一下:
```text
inline _syscall0(pid_t, gettid)
```
```text
static inline _syscall0(pid_t, gettid)
```
当然也可以这样:
在.h 头文件中:`extern "C" pid_t gettid(void);`
在.cpp 文件中:`_syscall0(pid_t, gettid)`
\_syscall0 是一个宏,定义一个函数的实现。
13. 下列编译告警是因为一个 static 类型的函数未被使用
```text
my.cpp:364: warning: 'int my_function(const cgicc::Cgicc&, const std::string&)' defined but not used
```
只需使用`__attribute__((unused))`修饰函数的声明即可:
```text
static int __attribute__((unused)) my_function(const cgicc::Cgicc&, const std::string&);
```
14. 执行 thrift 的 configure 时遇到如下的错误thrift-0.9.0 和 thrift-0.9.1 遇到过):
```text
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`,改为:
```text
CPPFLAGS="-I/usr/local/thirdparty/openssl/include" LDFLAGS="-ldl -L/usr/local/thirdparty/openssl/lib"
```
替代它就 OK 了。
15. 下面这个编译错误(表现为 g++进入死循环),可能是由于缺少右大括号`}`导致的,比如定义名字空间时少了`}`
```text
/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 文件所在目录下执行:
```text
/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. 下面这个编译错误,可能是因为在全局域内调用一个类对象的成员函数,全局域内是不能直接执行函的:
```text
error: expected constructor, destructor, or type conversion before '->' token
```
18. 下面这个错误是因为没有链接 OpenSSL 的 libcrypto 库,或者使用了静态库,而顺序不对:
```text
undefined symbol: EVP_enc_null
```
19. 下列是链接错误,不是编译错误,加上`-pthread`即可,注意不是`-lpthread`
```text
/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)时,如果
```text
./configure --prefix=/usr/local/thirdparty/libssh2-1.6.0 --with-libssl-prefix=/usr/local/thirdparty/openssl-1.0.2a
```
时遇到如下错误:
```text
configure: error: No crypto library found!
Try --with-libssl-prefix=PATH
or --with-libgcrypt-prefix=PATH
or --with-wincng on Windows
```
可以如下方法解决:
```text
./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`可能是因为如下原因:
```text
UserInfoInternal* user_info_internal = new UserInfoInternal;
delete user_info; // 这里应当是user_info_internal
```
22. 下面这个编译错误的原因是定义字符串宏时没有加双引引号:
```text
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++命令参数没写对,多了个`-`
```text
g++: -E or -x required when input is from standard input
```
如:
```text
CPPFLAGS=-pthread -
g++ -g -o $@ $^ $(CPPFLAGS) $(LDFLAGS)
```
24. `libjson_7.6.1`编译错误:
```text
makefile:180: Extraneous text after `else' directive
makefile:183: *** only one `else' per conditional. Stop.
```
解决办法:
找到 makefile 文件的第 180 行,将`else ifeq ($(BUILD_TYPE), debug)`,改成两行内嵌方式:
```text
# 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 行删除:
```text
cp -rv $(srcdir)/Dependencies/ $(include_path)/$(libname_hdr)/$(srcdir)
```
改成:
```text
cp -rv _internal/Dependencies/ $(include_path)/$(libname_hdr)/$(srcdir)
```
还有第 258 行前插入如一条命令:
```text
mkdir -p $(inst_path)
```
否则`cp -f ./$(lib_target) $(inst_path)`lib 将成库文件名。
25. 编译 gcc 时,如果遇到下面这个错误,这是因为运行时找不到 mpc、mpfr 和 gmp 的 so 文件:
```text
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
```
所以只需要如下操作下即可:
```text
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
```text
./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
```text
./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 时,如果遇到下面这个错误:
```text
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. 某次编译遇到如下这样一个链接错误:
```text
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 文件,将代码使用
```c
#ifdef __cplusplus
extern "C" {
#endif
```
修饰起来,或者直接使用`extern C`修饰函数 sdscatlen。
2. 不修改 redis 的代码,在引用 sds.h 时加上`extern "C" {`
```c
extern "C" {
#include "sds.h"
}`
```
上面两个办法均可,当然也可以考虑改用 g++编译 redis不过可能会遇到很多错误。
redis 对外供外部直接使用的头文件 hiredis.h 已使用了`extern "C" {`,所以不存在问题,只有当跳过 hiredis.h去使用一些内部头文件时需要注意一下。
3.
```text
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
```
这个错误,可能是存在和枚举等同名的字符串宏,比如存在下面的宏定义:
```text
enum DBTYPE
{
UNDEFINE = 0,
MYSQL_DB = 1,
ORACLE_DB = 2
};
```
而另一.h 文件中定义了宏:
`#define MYSQL_DB "mysql"`
29. 下面这个错误是因为类成员函数的声明和定义的返回值不相同
```text
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`
该编译错误原因是:
```text
CMessager:CMessager()
{
}
```
即少了个冒号:
```text
CMessager::CMessager()
{
}
```
31. `unable to find a register to spill in class SIREG`
编译时如果遇到这个错误,表示遇到一个 gcc 的 bug最简单的办法是去掉编译参数中的-O3 等优化项,然后再试可能就成功了,也可以考虑指定`-fno-schedule-insns`
32. 像下面这样一大堆乱七八糟的错误,可以考虑是否为少了`}`等引起的
```text
/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); }
```
比如:
```text
namespace A { namespace B {
。。。。。。
// 下面少了一个`}`
} // namespace A { namespace B {
```
33. `crc32 cannot be used as a function`
```text
uint32_t crc32 = crc32(0L, (const unsigned char*)crc32_str.data(), crc32_str.size());
```
错误是因为函数名和变量名相同了,可以改成如下解决:
```text
uint32_t crc32 = ::crc32(0L, (const unsigned char*)crc32_str.data(), crc32_str.size());
```
34.
```text
/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)
```
上面这个错误的意思是第一个参数的类型为
```text
void (*)(unsigned char, std::basic_string<char>, short unsigned int)
```
但传入的类型为
```text
void (*)(unsigned char, const std::basic_string<char>&, short unsigned int)
```
从上面的对比可以看出,要求函数的第二个参数为 std::string 类型,而不是 const std::string&类型。
35.
```text
conflicting declaration
has a previous declaration as
```
这个错误可能是因为头文件没有`#ifndef`,导致引入多次。
36.
```text
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`值,这个在运行时可能会触发`SIGILLIllegal instruction`,例如:
```text
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.
```text
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`对象类型。
````text
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;
}
```text
````