今天在Emacs编译代码过程中遇到了一个以前一直忽略的问题。
最近常用emacs中定义的compile command调用g++编译小demo,今天发现以前一段可以运行的代码在emace下编译无法运行,提示符号引用找不到,而所用的库和代码以前在slickedit下都完全正常。
其实问题出在编译命令的文件名顺序导致的链接依赖顺序不对,可气的是,这类问题以前还写过篇文章记录这个,但这么快就忘了。
c++编译成执行文件需要经过预处理、编译、链接几个阶段,分别对应不同的工具和命令参数,而通过g++可以用1条命令完成所有步骤。
虽然大部分gcc参数的顺序是无所谓的,但涉及到文件的参数必须按顺序摆放。
下面是那个编译失败的例子:
假设代码mutex.cpp中使用了boost::mutex,这使得生成执行文件时需要链接boost的thread库。
如果用下面命令编译:
g++ -IE:/workspace/c++/lib/boost_1_47_0 -LE:/workspace/c++/lib/boost_1_47_0/lib -lboost_thread-mgw45-mt-1_47 mutex.cpp -o mutex.exe
会出现如下一大堆错误:
E:\workspace\c++\boostDemo\thread>g++ -IE:/workspace/c++/lib/boost_1_47_0 -LE:/workspace/c++/lib/boost_1_47_0/lib -lboost_thread-mgw45-mt-1_
47 mutex.cpp -o mutex.exe
In file included from E:/workspace/c++/lib/boost_1_47_0/boost/thread/win32/thread_data.hpp:12:0,
from E:/workspace/c++/lib/boost_1_47_0/boost/thread/thread.hpp:15,
from E:/workspace/c++/lib/boost_1_47_0/boost/thread.hpp:13,
from mutex.cpp:1:
E:/workspace/c++/lib/boost_1_47_0/boost/thread/win32/thread_heap_alloc.hpp:59:40: warning: inline function 'void* boost::detail::allocate_ra
w_heap_memory(unsigned int)' declared as dllimport: attribute ignored
E:/workspace/c++/lib/boost_1_47_0/boost/thread/win32/thread_heap_alloc.hpp:69:39: warning: inline function 'void boost::detail::free_raw_hea
p_memory(void*)' declared as dllimport: attribute ignored
Info: resolving vtable for std::exception by linking to __imp___ZTVSt9exception (auto-import)
Info: resolving vtable for std::bad_exception by linking to __imp___ZTVSt13bad_exception (auto-import)
Info: resolving vtable for std::bad_alloc by linking to __imp___ZTVSt9bad_alloc (auto-import)
Info: resolving std::cout by linking to __imp___ZSt4cout (auto-import)
Info: resolving vtable for std::runtime_error by linking to __imp___ZTVSt13runtime_error (auto-import)
Info: resolving vtable for __cxxabiv1::__class_type_info by linking to __imp___ZTVN10__cxxabiv117__class_type_infoE (auto-import)
Info: resolving vtable for __cxxabiv1::__si_class_type_info by linking to __imp___ZTVN10__cxxabiv120__si_class_type_infoE (auto-import)
Info: resolving vtable for __cxxabiv1::__vmi_class_type_info by linking to __imp___ZTVN10__cxxabiv121__vmi_class_type_infoE (auto-import)
Info: resolving vtable for __cxxabiv1::__pointer_type_info by linking to __imp___ZTVN10__cxxabiv119__pointer_type_infoE (auto-import)
d:/tool/dev/c++/mingw/bin/../lib/gcc/mingw32/4.5.0/../../../../mingw32/bin/ld.exe: warning: auto-importing has been activated without --enab
le-auto-import specified on the command line.
This should work unless it involves constant data structures referencing symbols from auto-imported DLLs.
z:\temp\ccGMvhIY.o:mutex.cpp:(.text+0x145): undefined reference to `_imp___ZN5boost6thread4joinEv'
z:\temp\ccGMvhIY.o:mutex.cpp:(.text+0x152): undefined reference to `_imp___ZN5boost6thread4joinEv'
z:\temp\ccGMvhIY.o:mutex.cpp:(.text+0x15f): undefined reference to `_imp___ZN5boost6thread4joinEv'
z:\temp\ccGMvhIY.o:mutex.cpp:(.text+0x16c): undefined reference to `_imp___ZN5boost6threadD1Ev'
z:\temp\ccGMvhIY.o:mutex.cpp:(.text+0x184): undefined reference to `_imp___ZN5boost6threadD1Ev'
z:\temp\ccGMvhIY.o:mutex.cpp:(.text+0x191): undefined reference to `_imp___ZN5boost6threadD1Ev'
z:\temp\ccGMvhIY.o:mutex.cpp:(.text+0x1b5): undefined reference to `_imp___ZN5boost6threadD1Ev'
z:\temp\ccGMvhIY.o:mutex.cpp:(.text+0x1d5): undefined reference to `_imp___ZN5boost6threadD1Ev'
z:\temp\ccGMvhIY.o:mutex.cpp:(.text+0x1e6): more undefined references to `_imp___ZN5boost6threadD1Ev' follow
z:\temp\ccGMvhIY.o:mutex.cpp:(.text$_ZN5boost6threadC1IPFvPKcES3_EET_T0_[boost::thread::thread<void (*)(char const*), char const*>(void (*)(
char const*), char const*)]+0x3a): undefined reference to `_imp___ZN5boost6thread12start_threadEv'
z:\temp\ccGMvhIY.o:mutex.cpp:(.text$_ZN5boost6threadC1INS_3_bi6bind_tIvPFvPKcENS2_5list1INS2_5valueIS5_EEEEEEEET_NS_10disable_ifINS_14is_con
vertibleIRSD_NS_6detail13thread_move_tISD_EEEEPNS0_5dummyEE4typeE[boost::thread::thread<boost::_bi::bind_t<void, void (*)(char const*), boos
t::_bi::list1<boost::_bi::value<char const*> > > >(boost::_bi::bind_t<void, void (*)(char const*), boost::_bi::list1<boost::_bi::value<char
const*> > >, boost::disable_if<boost::is_convertible<boost::_bi::bind_t<void, void (*)(char const*), boost::_bi::list1<boost::_bi::value<cha
r const*> > >&, boost::detail::thread_move_t<boost::_bi::bind_t<void, void (*)(char const*), boost::_bi::list1<boost::_bi::value<char const*
> > > > >, boost::thread::dummy*>::type)]+0x2a): undefined reference to `_imp___ZN5boost6thread12start_threadEv'
z:\temp\ccGMvhIY.o:mutex.cpp:(.text$_ZN5boost6threadC1INS_8functionIFvvEEEEET_NS_10disable_ifINS_14is_convertibleIRS5_NS_6detail13thread_mov
e_tIS5_EEEEPNS0_5dummyEE4typeE[boost::thread::thread<boost::function<void ()()> >(boost::function<void ()()>, boost::disable_if<boost::is_co
nvertible<boost::function<void ()()>&, boost::detail::thread_move_t<boost::function<void ()()> > >, boost::thread::dummy*>::type)]+0x40): un
defined reference to `_imp___ZN5boost6thread12start_threadEv'
collect2: ld returned 1 exit status
上面的错误实际表明了4个信息:
1.由于这里是使用的boost动态库,boost的thread动态库涉及的代码需要链接gcc所实现的标准库,所以在编译过程中提示这些符号是auto-import的。
2.代码编译可以通过。
3.链接库文件g++能找到(如果找不到库文件不会是这种出错信息,信息会是“no such file”)
4.当mutex.cpp生成的obj链接时出现了无法找到boost thread库文件符号的问题。
一时没想到这个问题的原因。
但以前用slickedit使用同样的程序代码和链接库却是没问题的,所以问题还应该在编译命令的细节上。
slickedit下的编译使用的是一套通用的make文件,基本思路就是目录下源文件统统生成obj,然后obj统统链接生成exe或者lib。
其make文件中包含了compile和link的命令定义:
COMPILE=g++ -c -o "$(OUTDIR)/$(*F).o" $(CFG_INC) $<
LINK=g++ -o "$(OUTFILE)" $(ALL_OBJ)
毫无疑问,文本格式的code转化成exe执行文件,必然是先生成obj,而后链接,即使用g++一个命令这也不会有区别。
因此,注意到错误命令中cpp文件是出现在最后,所以问题原因应该是编译命令中cpp文件名的顺序决定了obj的顺序,而obj的顺序又决定了其依赖顺序。根据gcc的编译原则,如果A库依赖B库则B必须在命令行中放在A库后面(右面)
.参考以前的一篇博客:
到此问题就比较明了了,由于mutex.cpp在编译命令中的位置处于-lboost_thread-mgw45-mt-1_47之后(更右边)而mutex.cpp又依赖
thread库,cpp的顺序决定了在链接时所生成的mutex.obj会优先于boost_thread-mgw45-mt之前进行符号解析和链接,过早的链接导致了链接失败。
在编译命令中越靠前(更左边)的obj或者lib会越晚完成链接,因此在写编译命令时应该保证被依赖的库都应该在命令行中处于依赖它的库的后面(更右边)
因此正确的命令是:
g++ -IE:/workspace/c++/lib/boost_1_47_0 mutex.cpp -LE:/workspace/c++/lib/boost_1_47_0/lib -lboost_thread-mgw45-mt-1_47 -o mutex.exe
注意:-I放在的顺序是无所谓的,也就是说:
g++ mutex.cpp -IE:/workspace/c++/lib/boost_1_47_0 -LE:/workspace/c++/lib/boost_1_47_0/lib -lboost_thread-mgw45-mt-1_47 -o mutex.exe 这个命令也是没问题的,因为-I的所有包含文件都会在预处理阶段统一一次性完成,而不是像链接一样一个个obj链接。
也可以用两阶段指令完成生成exe,比如:
g++ -c mutex.cpp -IE:/workspace/c++/lib/boost_1_47_0
g++ -o mutex.exe mutex.o E:/workspace/c++/lib/boost_1_47_0/lib/libboost_thread-mgw45-mt-1_47.dll.a
注意如果这里的两个.o文件位置颠倒,就会出现和上面一样的错误了.
g++ -o mutex.exe E:/workspace/c++/lib/boost_1_47_0/lib/libboost_thread-mgw45-mt-1_47.dll.a mutex.o
严格来说这个问题其实和Emacs没有关系,只是由于emacs在调用M-x compile时可以通过定制命令行执行compile command来一次性调用g++生成执行文件,这样更容易曝露出这个问题,因为cpp在命令中的的位置隐式决定了其obj的链接顺序。
如果compile command定义成make文件则此问题不容易产生,因为写make文件的时候都会注意依赖关系,这样自动生成的g++编译命令都是符合被依赖的文件放后面的条件。
分享到:
相关推荐
本文研究了扩散方程中源项线性化处理问题,由张敏、胡文斌等研究者深入探讨,并提出了一种有效的微分方法,以期保证数值计算的稳定性和准确性。 扩散方程,通常表述为物理量随时间和空间变化的微分方程,尤其在热...
# 动态构建的艺术:CMake中源文件自动生成的秘诀 ## 引言 在当前的软件开发环境中,源文件的自动生成是一项至关重要的功能。它可以极大地减轻开发者的负担,减少重复工作,并提高整体的开发效率。对于大型项目而言...
4.tomcat源码在eclipse运行,重新编译,重新打包步骤文件 5.一个tomcat源码在eclipse上运行的java工程 作用: 1.用于学习tomcat源码和了解tomcat运行机制 2.学习如何修改tomcat源码后如何重新编译,打包。
同时,报告明确表示公司财务状况的健康,不存在被控股股东非经营性占用资金和违反规定对外担保的问题,这进一步证实了中源家居在财务管理上的规范性和透明度。 经营情况讨论与分析部分详细阐述了公司面临的一系列...
如果跨驱动器操作,则可能需要先复制再删除源文件,以防在复制过程中源文件被意外修改或删除。此外,考虑到多线程环境,可能需要添加同步机制,以防止并发操作导致的数据不一致问题。 总之,易语言提供了丰富的文件...
中源FR1000软起动器是一种应用于三相交流电动机起动和保护的高科技产品。它具备高性能、高品质以及小体积等特点,采用现代控制原理,并且应用了模块化设计和双CPU控制。中源FR1000系列软起动器符合国际质量标准ISO...
它定义了项目中源文件的编译规则,包括哪些文件需要编译,何时需要重新编译,以及如何链接生成最终的可执行文件。makefile的重要性在于它能够极大地提高软件开发效率,尤其是在处理大型工程项目时,它能够清晰地管理...
基于matlab代码编程的问题 第1章 初识MATLAB 第2章 MATLAB入门操作 第3章 MATLAB数据类型 第4章 矩阵运算 第5章 程序设计 第6章 图形可视化 第7章 图形用户界面(GUI 第8章 数值分析 第9章 符号计算 第10章 ...
文件系统是操作系统的重要组成部分,实现对底层存储介质的抽象,为用户提供优雅的接口,包括目录以及文件操作等等。文件系统大致可以分成磁盘文件系统,网络文件系统和其他满足特殊需求的文件系统等。本实验重点关注...
中源动力DF900-A系列变频器说明书pdf,中源动力DF900-A系列变频器说明书
0132_极智AI_解读ubuntu和win10中源码编译tvm的方法
`file_system.depend` 文件可能包含了项目中源文件之间的依赖关系,这对于构建系统理解何时需要重新编译某些文件至关重要。当源代码修改后,构建系统会依据这些依赖关系决定哪些目标文件需要更新。 `file_system....
根据提供的文件内容,中源动力DF800变频器485通讯协议V1.1完整版包含了以下知识点: 1. 中源动力DF800变频器通讯协议简介: - 中源动力DF800变频器支持RS485通讯接口,具备相应的通讯协议用于实现与外部设备的数据...
java 读取txt文本文件中的数据并保存到数据库中源代码,假设txt已有格式,并以","分隔。其中的sql包需要自己去微软官网下载。
编译文件中包含libevent-2.1.12-stable.tar.gz,openssl-1.1.1l.tar.gz,zlib-1.2.12.tar.gz,都是在 centos7 中使用 gcc 9.3.1 编译
编译文件中包含libevent-2.1.12-stable.tar.gz,openssl-1.1.1l.tar.gz,zlib-1.2.12.tar.gz,都是在 centos7 中使用 gcc4.8.5 编译
根据提供的文件信息,中源动力E900系列变频器使用说明书所包含的主要知识点有: 产品简介:文档开篇可能会介绍E900系列变频器的概述,包括其基本功能、设计用途、系列范围(0.2~630KW),以及为何称其为“环保节能...
中源家居:首次公开发行股票招股说明书.PDF
另外,提供的文件"编译Qt源码.pdf"可能是编译过程的详细指南或注意事项,建议阅读以获取更具体的信息。而".emmx"文件格式不常见,可能是一种特定的思维导图文件,与编译过程关系不大,如果需要打开,确保证明已安装...
《中源动力FR1000系列电机软启动器使用手册》是一份详细的指导文档,旨在帮助用户理解和操作中源动力公司生产的FR1000系列电机软启动器。软启动器是一种现代化的电机控制设备,它能有效地降低电动机在启动时的电流...