简体   繁体   中英

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 . For the latter, both full source open62541.c/.h and a library libopen62541.a exist. 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++.

I can get my.cpp to compile successfully by referencing the 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 .

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.

I can get compilation to succeed by using the -fpermissive switch:

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:

#ifdef __cplusplus
extern "C" {
#endif
  1. 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? Why does one work and the other doesn't?

  2. Should one method - linking .a vs referring to .c - be preferred to another? I was under impression that they should be equivalent, but apparently they aren't.

  3. Is using -fpermissive in this case more of a hack that could mask potential problems, and should thus be avoided?

The error (and warning) you see are compilation errors (and warning) output by a C++ compiler when compiling C code.

For instance, in C "literal" has type char[] while in C++ it has type const char[] .

Would you get a C++ compiler build libopen62541.a from open62541.c , you would see the same errors (warnings). But a C compiler might be OK with it (depending on the state of that C source file).

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).


From here, you basically have two options:

  1. Use the procompiled library if it suits you as is

     g++ -std=c++14 -Wall -Wextra -Werror my.cpp -lopen62541.a -o out 
  2. 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++. That file apparently contains constructs that are valid in C but not 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.

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! 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM