clang: stripping class names from the output - c++

I build a C++ project of mine using clang++, using the following command line command (split into lines):
clang++
-std=c++11
-W -Wall -Wextra -pedantic -Wno-newline-eof -Werror
-O4
-I<dirs>
-L<dirs>
-l<libs>
-framework <frameworks>
-D <defs>
-o <filename>
<files>
However, when I run strings <filename>, several class names show up, despite the -O4 in the command line. I've tried -Wl,-s which should tell llvm to strip all symbols, but that doesn't remove these.
The class names that show up seem to all have one thing in common: they have a vtable. One of these classes is :
class MyClass {
public:
virtual void myFunc() = 0;
};
It shows up as the symbol :
N9namespace7MyClassE
I don't like it that my namespace and class names show up in the final file. How do I strip these? My binary is a command line utility, so only the main function should be exported.
Even after supplying -fno-rtti (as suggested by #n.m.), some names still remain, such as :
__ZN15MyClassInstance6myFuncEv
(MyClassInstance being a subclass of the MyClass above)
Additionally, even the names of global variables are in the binary.

I solved this by supplying the clang argument -fno-rtti, which disables RTTI, a C++ feature I don't use anyway.
[edit]
It looks like -O4 does not imply strip, and the last few references to my class names can be removed by executing strip.

Related

emscripten Linking globals named symbol multiply defined

I have a c++ CMAKE (VERSION 3.10.2 -std=c++17 ) project that i am able to compile and link with bought gcc and clang. Bought of them produce the target binaries which work as expected. Recently i decided to to try and add another target i.e. webassembly. The project is compiling as expect, however when the EMscripten build is being executed i.e. in the linking phase i get the following error:
Elapsed time: 1 s. (time), 0.002241 s. (clock)
[100%] Linking CXX executable wasmExec.js
cd /Projects/time/time.cpp/build/src/wasm && /usr/bin/cmake -E cmake_link_script CMakeFiles/wasmExec.dir/link.txt --verbose=1
/Projects/emscripten/emsdk/emscripten/1.38.12/em++ -s WASM=1 -s NO_EXIT_RUNTIME=1 -s VERBOSE=1 --pre-js /Projects/time/time.cpp/src/wasm/preModule.js -s DEMANGLE_SUPPORT=1 -s DISABLE_EXCEPTION_CATCHING=0 -s ERROR_ON_UNDEFINED_SYMBOLS=0 #CMakeFiles/wasmExec.dir/objects1.rsp -o wasmExec.js #CMakeFiles/wasmExec.dir/linklibs.rsp
error: Linking globals named '_ZTVN9timeproto3time8defaults20TimeDefaultParametersE': symbol multiply defined!
WARNING:root:Note: Input file "#/tmp/tmpUeJ6zc.response" did not exist.
ERROR:root:Failed to run llvm optimizations:
When i do
c++filt _ZTVN9timeproto3time8defaults20TimeDefaultParametersE
i get
vtable for timeproto::time::defaults::TimeDefaultParameters
from another answer by Stackoverflow i.e.
Possible reasons for symbol multiply defined other than 'extern'
i do understand that i have defined this class more then once, however my problem is that i can not locate that place where i have made the mistake with the second definition. In the previous answer the person had the hint i.e. the cpp file where that he has made that mistake but in my case emscipten is not so generous.
This class is used all over the code base in many many files and after long manual searching i was not able to find anything that can point me at least to the localtion of the second definition. Thus i was hoping that someone can help me with the following questions
1) how can this be troubleshoot further in order to find where exactly the second defintion of the class is occuring, maybe a flag by gcc or clang ?
2) why this error is beeing displayed only when I am trying to compile/build the webassmbly target. The regular Linux64 build target is successefull and the test are also working correctly.
3) I am running cmake with following "add_definitions" i.e.
if(UNIX)
add_definitions(" -pedantic -pedantic-errors -W ")
add_definitions(" -Wall -Wextra -Werror -Wshadow -Wnon-virtual-dtor ")
add_definitions(" -v ")
# add_definitions(" -Worl-style-cast -Wcast-align ")
# add_definitions(" -Wunused -Woverloaded-virtual ")
add_definitions(" -g ")
endif(UNIX)
if the TimeDefaultParameters has been defined more then once should't clang not complain also for linux build with the above "add_definitions" ?
here is the code below TimeDefaultParameters.cpp This is a very simple file that does not contain any object instead it has 43 "static const uint32_t" variables.
#include "TimeDefaultParameters.h"
namespace timeproto::time::defaults
{
TimeDefaultParameters::TimeDefaultParameters() {
}
TimeDefaultParameters::~TimeDefaultParameters() {
}
const uint32_t TimeDefaultParameters::SIGNED_SHORT_MAX_VALUE = 32767;
.... (another 42 static const uint32_t)
}
and the header file TimeDefaultParameters.h:
#ifndef _TIME_DEFAULT_PARAMETERS_
#define _TIME_DEFAULT_PARAMETERS_
#include <stdint.h>
namespace timeproto::time::defaults
{
class TimeDefaultParameters final
{
public:
explicit TimeDefaultParameters();
virtual ~TimeDefaultParameters();
static const uint32_t SIGNED_SHORT_MAX_VALUE;
.....
.... (another 42 static const uint32_t)
};
}
#endif //#ifndef _TIME_DEFAULT_PARAMETERS_
in cmake i have the set my target properties like:
set_target_properties(wasmExec PROPERTIES LINK_FLAGS "-s WASM=1 -s NO_EXIT_RUNTIME=1 -s VERBOSE=1 --pre-js /Projects/time/time.cpp/src/wasm/preModule.js -s DEMANGLE_SUPPORT=1 -s DISABLE_EXCEPTION_CATCHING=0 -s ERROR_ON_UNDEFINED_SYMBOLS=0" )
this is how i am calling cmake to make the build from withing the build directory
emconfigure cmake -DCMAKE_BUILD_TYPE=Emscripten -G "Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=/Projects/emscripten/emsdk/emscripten/1.38.12/cmake/Modules/Platform/Emscripten.cmake ../
make -j8
any ideas are greatly appreciated.
ADDITION: 05 January 2020
I was able to find a workaround for this problem but i still it leaves some questions of the nature of the error.
The class in question was part of the archive that was created and loaded dynamically i.e. i had used in the CMAKE part for this library "set(LIB_TYPE SHARED)".
here is full example how cmake generated that archive i.e. the CMakeLists.txt.
set( TIME_DEFAULTS_SRC
...
TimeDefaultParameters.h TimeDefaultParameters.cpp
...
)
set(LIB_TYPE STATIC)
#set(LIB_TYPE SHARED)
add_library(time_defaults ${LIB_TYPE} ${TIME_DEFAULTS_SRC} )
target_include_directories(time_defaults PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/")
I have changed from dynamic to static and i was able to create the wasm no errors were shown. During the compilation i also saw somewhere in between of the compilation process some warrning i.e. :
WARNING:root:When Emscripten compiles to a typical native suffix for shared libraries (.so, .dylib, .dll) then it emits an LLVM bitcode file. You should then compile that to an emscripten SIDE_MODULE (using that flag) with suffix .wasm (for wasm) or .js (for asm.js). (You may also want to adapt your build system to emit the more standard suffix for a file with LLVM bitcode, '.bc', which would avoid this warning.)
this warrning is now gone. But it is very easy to oversee thing like that especially if the compilation process is taking long time. However my understanding is that the very first error message tells us , "look you have made duplicate definition of some symbol in your code go find the place and make sure that the class is define only once". That was exactly what i was doing i.e. searching the code base for that duplicate definition. Thus now the question is: Why emscripten have a problem does with dynamic linking i.e. i know that it is officially supported i.e.
https://webassembly.org/docs/dynamic-linking/
and is that the source of the error at all or is something else?
Why this error disappears when i change to static. I can reproduce this by simply changing library type!
I think i already found the answer here
https://github.com/emscripten-core/emscripten/wiki/Linking
So the solution in my case was to find the occurrences in the CMAKE file where the library was added dynamically and change that to static linking i.e.
#set(LIB_TYPE SHARED)
set(LIB_TYPE STATIC)

silly C++ syntax has not been declared

I'm trying to take a Qt C++ project originally written for Windows and cross compile it for embedded Linux. Now this program compiles find and works on Windows, so this problem must be something OS specific (which I didn't think happend with Qt code) or configuration related, but I'm having a hard time tracking it down because I don't fully understand C++ syntax.
my make command:
arm-linux-gnueabihf-g++ -c -march=armv7-a -marm -mthumb-interwork
-mfloat-abi=hard -mfpu=neon -mtune=cortex-a8 -O2 -O3 -Wall -W -D_REENTRANT -DCHL80Net -DPHASE_TO_NEUTRAL -DCHL80NET -DCANLCD_BUILD -DQT_NO_DEBUG -DQT_XML_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I../mkspecs/qws/linux-am335x-g++ -I. -I../include/QtCore -I../include/QtGui -I../include/QtXml -I../include -I. -IApp -IApp/Model/ModelSim -IApp/Model -I. -IPages -IApp/GUI/Widgets -IApp/GUI/Pages -IApp/GUI -IApp/GUI/Widgets -IApp/GUI/Pages/Util -IApp/GUI/Pages -IApp/Log4Qt -I.obj -o .obj/CanInterface.o App/Can/CanInterface.cpp
The error:
App/Can/CanInterface.cpp: In member function ‘void
CanInterface::closeConnection()’: App/Can/CanInterface.cpp:68:5:
error: ‘::close’ has not been declared make: * [.obj/CanInterface.o]
Error 1
Here's the line of code in question:
void CanInterface::closeConnection()
{
::close(m_socket);
m_socket = -1;
I thought this didn't look like valid code at all at first, but I don't really know C++ so I had to do a little research, it seems like this ::function() syntax is to ensure resolution occurs from the global namespace instead of the local one.
So what I'm trying to find out is what namespace should have declaired this close() function. If my understanding of this code is correct I don't need to look in the CanInterface class for the undeclaired function, but it's parent class?
In the header file for the CanInterface class I found this:
class CanInterface : public QObject
{
Q_OBJECT
which I think means that it inharents from a QObject class. So:
Am I on the right track?
How do I know if I need to look at the QObject class for the missing close() function or if I need to keep going up? Does ::close somehow tell me how many levels of nested classes I need to search through?
Any other ideas or tips for further investigating this?
You are correct, in that ::some_function() calls a function from the global scope.
This includes all C library or system functions. You can lookup global functions on a *nix system with man, e.g.
man close
which gives on my Ubuntu
NAME
close - close a file descriptor
SYNOPSIS
#include <unistd.h>
int close(int fd);
So, to fix your compile error, you must include unistd.h somewhere in your C++ source or in a surrounding header file.
You can get the same information, when you google for man close, e.g. http://linux.die.net/man/2/close
C++ encapsulates names in namespaces to avoid naming collisions. It's somewhat analagous to the C practice of prepending a prefix specific to a library to the names of functions in that library, e.g., my_library_foo() in C might be called my_library::foo() in C++. When :: appears at the beginning of a name, it means that name is fully qualified: it is looked up beginning from the global namespace instead of the current/enclosing namespace, much like with absolute (/etc/passwd/) vs. relative (foo/bar) file names.
So the name ::close is intended to resolve to the close function declared in the global namespace, the one which would be put there by including <unistd.h> on a POSIX system.

Cross-build, link issue

I have to build a small program to run on a set-top box, and for that I use a specific build toolchain: toolchain-final-mipsisa32r2el-timesys-linux-gnu
The build is composed of 2 parts: one lib static .a file and an executable that use the library.
The lib is correctly build with the following option:
mipsisa32r2el-timesys-linux-gnu-gcc -c --param max-inline-insns-single=2400
-o ../../../build/LinuxHost_STB_release/_outLib/STB.o -O2 -fno-strict-aliasing
-Winline -Wall -I../../../Modules -I../../../Source
-I/opt/toolchains/toolchain-final-mipsisa32r2el-timesys-linux-gnu/include
-I -fno-rtti ../../../Source/STBLib/STB.cpp
if I run nm on the libSTB.a, I saw the function define in STB.cpp as:
0000000000000124 T STB_Create
0000000000000460 T STB_Destroy
To compile and link the executable, I use the following command line:
mipsisa32r2el-timesys-linux-gnu-c++ -o ../../../build/LinuxHost_STB_release/STBExample
--sysroot=/opt/toolchains/toolchain-final-mipsisa32r2el-timesys-linux-gnu/
-I/opt/toolchains/toolchain-final-mipsisa32r2el-timesys-linux-gnu/include
-L../../../build/LinuxHost_STB_release
-lSTB ../../../Source/STBLib/STBExample.c
But I get the following linker error:
STBExample.c:(.text+0x488): undefined reference to `STB_Create'
Any idea of where I made a mistake or on how to investigate ?
As explained by #H2CO3 and #Joe Z, the problem was in the parameter ordering.
Additional static lib set with -lmust be place AFTER the .c file. As in the following example, a switch of the 2 last arguments solved the issue.
mipsisa32r2el-timesys-linux-gnu-c++ -o ../../../build/LinuxHost_STB_release/STBExample
--sysroot=/opt/toolchains/toolchain-final-mipsisa32r2el-timesys-linux-gnu/
-I/opt/toolchains/toolchain-final-mipsisa32r2el-timesys-linux-gnu/include
-L../../../build/LinuxHost_STB_release
../../../Source/STBLib/STBExample.c -lSTB

Configuring g++ from Code::Blocks doesn't take affect on command line

I'm trying to change the settings of g++ from the Code::Blocks IDE. I went to the Settings tab, clicked Compiler... and checked various options for the compiler to use, like
Enable all warnings (-Wall)
Have g++ follow the C++11 ISO C++ language standard (-std=c++11)
......
These are just two of many others; when I compile on the command line, here is what comes up:
g++ -o example example.cpp
# warning: initializer lists only available with -std=c++11 ...
Notice how there's no warning either - I have an unused variable in my program. It only works if I give the options manually:
g++ -Wall -std=c++11 -o example example.cpp
Do you think I might have done something wrong when setting up the compiler? Why aren't the options taking affect?
Invoking the compiler from the ide is completely independent from doing it in a command line shell. There's no reason for the setting and usage of one to have any effect on the other.

Get the compiler options from a compiled executable?

It there a way to see what compiler and flags were used to create an executable file in *nix? I have an old version of my code compiled and I would like to see whether it was compiled with or without optimization. Google was not too helpful, but I'm not sure I am using the correct keywords.
gcc has a -frecord-gcc-switches option for that:
-frecord-gcc-switches
This switch causes the command line that was used to invoke the compiler to
be recorded into the object file that is being created. This switch is only
implemented on some targets and the exact format of the recording is target
and binary file format dependent, but it usually takes the form of a section
containing ASCII text.
Afterwards, the ELF executables will contain .GCC.command.line section with that information.
$ gcc -O2 -frecord-gcc-switches a.c
$ readelf -p .GCC.command.line a.out
String dump of section '.GCC.command.line':
[ 0] a.c
[ 4] -mtune=generic
[ 13] -march=x86-64
[ 21] -O2
[ 25] -frecord-gcc-switches
Of course, it won't work for executables compiled without that option.
For the simple case of optimizations, you could try using a debugger if the file was compiled with debug info. If you step through it a little, you may notice that some variables were 'optimized out'. That suggests that optimization took place.
If you compile with the -frecord-gcc-switches flag, then the command line compiler options will be written in the binary in the note section. See also the docs.
Another option is -grecord-gcc-swtiches (note, not -f but -g). According to gcc docs it'll put flags into dwarf debug info. And looks like it's enabled by default since gcc 4.8.
I've found dwarfdump program to be useful to extract those cflags. Note, strings program does not see them. Looks like dwarf info is compressed.
As long as the executable was compiled by gcc with -g option, the following should do the trick:
readelf --debug-dump=info /path/to/executable | grep "DW_AT_producer"
For example:
% cat test.c
int main() {
return 42;
}
% gcc -g test.c -o test
% readelf --debug-dump=info ./test | grep "DW_AT_producer"
<c> DW_AT_producer : (indirect string, offset: 0x2a): GNU C17 10.2.0 -mtune=generic -march=x86-64 -g
Sadly, clang doesn't seem to record options in similar way, at least in version 10.
Of course, strings would turn this up too, but one has to have at least some idea of what to look for as inspecting all the strings in real-world binary with naked eyes is usually impractical. E.g. with the binary from above example:
% strings ./test | grep march
GNU C17 10.2.0 -mtune=generic -march=x86-64 -g -O3
This is something that would require compiler support. You don't mention what compiler you are using but since you tagged your question linux I will assume you are using gcc -- which does not default the feature you're asking about (but -frecord-gcc-switches is an option to perform this).
If you want to inspect your binary, the strings command will show you everything that appears to be a readable character string within the file.
If you still have the compiler (same version) you used, and it is only one flag you're unsure about, you can try compiling your code again, once with and once without the flag. Then you can compare the executables. Your old one should be identical, or very similar, to one of the new ones.
I highly doubt it is possible:
int main()
{
}
When compiled with:
gcc -O3 -ffast-math -g main.c -o main
None of the parameters can be found in the generated object:
strings main | grep -O3
(no output)