[英]Why does gcc produce a different result when bulding from source compared to linking a static library?
I have a single C++14 file, my.cpp
, and from within it I'm trying to use a C99 library called open62541 . 我有一个C ++ 14文件my.cpp
,并且在其中尝试使用一个名为open62541的C99库。 For the latter, both full source open62541.c/.h
and a library libopen62541.a
exist. 对于后者,完整源代码open62541.c/.h
和库libopen62541.a
存在。 In my.cpp
, where I include the open62541.h
, I'm using C++ specific code (eg iostream), so technically I'm mixing C and C++. 在my.cpp
,其中包括open62541.h
,我使用的是C ++特定代码(例如iostream),因此从技术上讲,我正在混合C和C ++。
I can get my.cpp
to compile successfully by referencing the libopen62541.a
: 我可以my.cpp
通过引用成功编译libopen62541.a
:
gcc -x c++ -std=c++14 -Wall my.cpp -l:libopen62541.a -lstdc++ -o out
This outputs no warnings, and creates an executable out . 这不会输出任何警告,并创建一个可执行文件out 。
However, if I try to compile using source code only: 但是,如果我尝试仅使用源代码进行编译:
gcc -x c++ -std=c++14 -Wall my.cpp open62541.c -lstdc++ -o out
I get a lot of ISO C++ warnings (eg " ISO C++ forbids converting a string constant to 'char '*") and some " jump to label " errors originating from within open62541.c
, resulting in compilation failure. 我收到很多ISO C ++警告(例如,“ ISO C ++禁止将字符串常量转换为'char '*”)和源自open62541.c
一些“ 跳转到标签 ”错误,导致编译失败。
I can get compilation to succeed by using the -fpermissive
switch: 我可以使用-fpermissive
开关使编译成功:
gcc -x c++ -std=c++14 -Wall my.cpp open62541.c -lstdc++ -fpermissive -o out
which still outputs a lot of warnings, but creates the executable successfully. 仍然会输出很多警告,但会成功创建可执行文件。 However, I'm unsure if doing this is a good idea. 但是,我不确定这样做是否是个好主意。
Perhaps worth mentioning is that open62541.h
considers C++ at the beginning: 也许值得一提的是open62541.h
在一开始就考虑使用C ++:
#ifdef __cplusplus
extern "C" {
#endif
Given that .a library, which comes bundled with the open62541 library code, is supposedly built from the same source, why are the first two approaches not consistent in terms of warnings and errors generated? 假设与open62541库代码捆绑在一起的.a库是从同一源构建的,为什么前两种方法在生成警告和错误方面不一致? Why does one work and the other doesn't? 为什么一个起作用而另一个不起作用?
Should one method - linking .a vs referring to .c - be preferred to another? 链接.a与引用.c的一种方法是否应该优先于另一种方法? I was under impression that they should be equivalent, but apparently they aren't. 我的印象是它们应该等效,但显然不是。
Is using -fpermissive
in this case more of a hack that could mask potential problems, and should thus be avoided? 在这种情况下,使用-fpermissive
是否更多是可以掩盖潜在问题的技巧,因此应避免使用?
The error (and warning) you see are compilation errors (and warning) output by a C++ compiler when compiling C code. 您看到的错误(和警告)是C ++编译器在编译C代码时输出的编译错误(和警告)。
For instance, in C "literal"
has type char[]
while in C++ it has type const char[]
. 例如,在C中, "literal"
类型为char[]
而在C ++中,其类型为const char[]
。
Would you get a C++ compiler build libopen62541.a
from open62541.c
, you would see the same errors (warnings). 您会从open62541.c
得到一个C ++编译器libopen62541.a
open62541.c
,您将看到相同的错误(警告)。 But a C compiler might be OK with it (depending on the state of that C source file). 但是C编译器可能会满意(取决于该C源文件的状态)。
On the other hand, when you compile my.cpp
and links it against libopen62541.a
, the compiler doesn't see that offending C code, so no errors (warnings). 另一方面,当编译my.cpp
并将其链接到libopen62541.a
,编译器不会看到该冒犯的C代码,因此不会出现错误(警告)。
From here, you basically have two options: 从这里开始,您基本上有两个选择:
Use the procompiled library if it suits you as is 如果适合您,请使用预编译的库
g++ -std=c++14 -Wall -Wextra -Werror my.cpp -lopen62541.a -o out
Compile the library's code as a first step if you need to modify it 如果需要修改,请先编译库的代码
gcc -Wall -Wextra -Werror -c open62541.c g++ -std=c++14 -Wall -Wextra -Werror -c my.cpp g++ open62541.o my.o -o out
gcc -x c++ -std=c++14 -Wall my.cpp open62541.c -lstdc++ -o out
This command forces the C code in open62541.c
to be compiled as C++. 此命令强制将open62541.c
的C代码编译为C ++。 That file apparently contains constructs that are valid in C but not C++. 该文件显然包含在C中有效的构造,但在C ++中无效。
What you should be doing is compiling each file as its own language and then linking them together: 您应该做的是将每个文件编译为自己的语言,然后将它们链接在一起:
gcc -std=gnu11 -Wall -c open62541.c
g++ -std=gnu++14 -Wall -c my.cpp
g++ -o out my.o open62541.o
Wrapping up those commands in an easily repeatable package is what Makefiles are for. 将这些命令包装在易于重复的软件包中是Makefile的作用。
If you're wondering why I changed from the strict -std=c++14
to the loose -std=gnu++14
mode, it's because the strict mode is so strict that it may break the system headers! 如果您想知道为什么我从严格的-std=c++14
更改为宽松的-std=gnu++14
模式,那是因为严格的模式是如此严格,以至于可能破坏系统头文件! You don't need to deal with that on top of everything else. 您无需在所有其他事情上都进行处理。 If you want a more practical additional amount of strictness, try adding -Wextra and -Wpedantic instead ... but be prepared for that to throw lots of warnings that don't actually indicate bugs, on the third-party code. 如果您希望获得更多实用性的严格性,请尝试添加-Wextra和-Wpedantic ...,但是为此准备好在第三方代码上抛出很多实际上并不指示错误的警告。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.