Including unused code during compilation - c++

Building my application from Makefile I have found that excluding from code some class and its using doesn't affected on size of the built application.
// some file
// #include "SomeClass.h"
.......
void myfunc()
{
SomeClass _cl;
// do something with _cl etc...
// _cl.SomeFunc();
.........
}
Makefile
......
SOURCES = ... SomeClass.cpp .... etc
But If I remove SomeClass.cpp from Makefile then size of the built application really becomes less. Why gcc doesn't optimize compiled code and don't exclude unused SomeClass from final result?

You can configure this through compile flags. On linux/gcc, unused symbols are not eliminated from the binary - they may be of use when you dl_open() a binary. If you want to eliminate unused code, add -ffunction-sections and -fdata-sections to your compile options and --gc-sections to your linker options. The compile options will ensure that every function is placed in a separate section (as opposed to a section per file), the linker option will throw unused sections away.

Related

clang-tidy - ignore third party headers code

I'm using CMake for my project and I wanted to introduce clang-tidy checks to the project.
I'm using for this purpose CMAKE_CXX_CLANG_TIDY and .clang-tidy file for checks setup.
I wanted to use warnings-as-errors to have reliable way in CI to check whether commit introduces some new violations. Unfortunately I have some problems with enabling checks due to 3rd-party libraries.
PLEASE LOOK AT EDIT2!
For example I use Eigen which is header-only library. Due to this fact I get some warnings in my code eg. "a_file.cpp"
/snap/cmake/301/bin/cmake -E __run_co_compile --tidy="clang-tidy;--extra-arg-before=--driver-mode=g++" --source=../../a_file.cpp -- /usr/bin/clang++ -DEIGEN_MPL2_ONLY -DEIGEN_STACK_ALLOCATION_LIMIT=16384 -I../../SomePath -I../../SomePath2 -isystem ../../path_to/include/Eigen -m64 -stdlib=libc++ -g -fPIC -std=c++11 -MD -MT a_file.cpp.o -MF a_file.cpp.o.d -o a_file.cpp.o -c a_file.cpp
../../path_to/include/Eigen/Eigen/src/Core/Swap.h:89:36: error: Assigned value is garbage or undefined [clang-analyzer-core.uninitialized.Assign,-warnings-as-errors]
a_file.cpp:279:5: note: Loop condition is true. Entering loop body
for( unsigned int i = 0; i < 100; ++i )
^
a_file.cpp:282:13: note: Calling move assignment operator for 'Matrix<float, 3, 1, 0, 3, 1>'
some_name = Vector3f( GetRandom( fDummy ),GetRandom( fDummy ), GetRandom( fDummy ) );
I'm a bit out of ideas how to ignore this kind of problems as header-filter doesn't seem to resolve this issue - for other checks [bugprone-xxx] I have similar issues. What are my options besides adding //NO-LINT everywhere?
Edit: added a bit of context to error.
EDIT2:
As I still struggle with correct handling for clang-tidy I've prepared a repository to show the example problem.
https://github.com/MaciejPatro/test_clang_tidy
This is a minimal repository with 2 header files, and one cpp files that uses doctest. I use two checks there: clang-analyzer-cplusplus*,google-readability-todo - first one demonstrating the problem with doctest inclusion and second one because it's the simplest one to create a "bug".
some_header.h
void else_after_return() {
// TODO wrong hpp some
}
other_header.h
void wrong_function() {
// TODO wrong hpp other
}
my_test.cpp
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include <doctest/doctest.h>
#include <some_header.h>
#include <other_header.h>
TEST_CASE("a test")
{
// TODO wrong cpp
else_after_return();
wrong_function();
CHECK(5 != 7);
}
There are 3 tests that give these results:
Ignore header files (no --header-filter specified).
I can see:
/home/pmac/projects/test_clang_tidy/source/tests/my_test.cpp:9:3: warning: missing username/bug in TODO [google-readability-todo]
Which is expected
Allow all header files ( --header-filter=.* )
I can see:
/home/pmac/projects/test_clang_tidy/source/include/other_header.h:5:3: warning: missing username/bug in TODO [google-readability-todo]
/home/pmac/projects/test_clang_tidy/source/include/some_header.h:5:3: warning: missing username/bug in TODO [google-readability-todo]
/home/pmac/projects/test_clang_tidy/source/tests/my_test.cpp:9:3: warning: missing username/bug in TODO [google-readability-todo]
Which makes sense for me
Only header files with "some in name" (--header-filter=.some.)
/home/pmac/projects/test_clang_tidy/source/include/some_header.h:5:3: warning: missing username/bug in TODO [google-readability-todo]
/home/pmac/projects/test_clang_tidy/source/tests/my_test.cpp:9:3: warning: missing username/bug in TODO [google-readability-todo]
Everything seems fine
Next 3 tests add the second check clang-analyzer-cplusplus which is visible in doctest. Now regardless of the settings provided to clang-tidy I get additionally a warning from doctest MACRO DOCTEST_DO_BINARY_EXPRESSION_COMPARISON which is expanded from CHECK:
/home/pmac/.conan/data/doctest/2.4.6/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/doctest/doctest.h:1239:9: warning: Potential leak of memory pointed to by field 'ptr' [clang-analyzer-cplusplus.NewDeleteLeaks]
I want the warning from doctest being filtered out - unfortunately none of settings (--header-filter, nor including it as system header -isystem) allows me to ignore it.
Here is the full command line how the my_test.cpp is compiled (to confirm that doctest header is included with -isystem)
/home/pmac/.local/lib/python3.8/site-packages/cmake/data/bin/cmake -E __run_co_compile --tidy="clang-tidy-12;-checks=-*,clang-analyzer-cplusplus*,google-readability-todo;--header-filter=.*some.*;--extra-arg-before=--driver-mode=g++" --source=../source/tests/my_test.cpp -- /usr/bin/c++ -I../source/include -isystem /home/pmac/.conan/data/doctest/2.4.6/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include -g -std=gnu++2a -MD -MT source/CMakeFiles/test_clang_tidy_tests.dir/tests/my_test.cpp.o -MF source/CMakeFiles/test_clang_tidy_tests.dir/tests/my_test.cpp.o.d -o source/CMakeFiles/test_clang_tidy_tests.dir/tests/my_test.cpp.o -c ../source/tests/my_test.cpp
Is there any other way to filter out the warning generated by MACROs included from a 3rd party library? I don't want to remove checks in my tests because of 3rdparty library.
To change "Tests" in repository comment/uncomment lines in https://github.com/MaciejPatro/test_clang_tidy/blob/master/CMakeLists.txt
set(CMAKE_CXX_CLANG_TIDY "clang-tidy-12;-checks=-*,google-readability-todo")
#set(CMAKE_CXX_CLANG_TIDY "clang-tidy-12;-checks=-*,google-readability-todo;--header-filter=.*")
#set(CMAKE_CXX_CLANG_TIDY "clang-tidy-12;-checks=-*,google-readability-todo;--header-filter=.*some.*")
# Something works wrong here!
#set(CMAKE_CXX_CLANG_TIDY "clang-tidy-12;-checks=-*,clang-analyzer-cplusplus*,google-readability-todo)
#set(CMAKE_CXX_CLANG_TIDY "clang-tidy-12;-checks=-*,clang-analyzer-cplusplus*,google-readability-todo;--header-filter=.*")
#set(CMAKE_CXX_CLANG_TIDY "clang-tidy-12;-checks=-*,clang-analyzer-cplusplus*,google-readability-todo;--header-filter=.*some.*")
The error you have posted does not look spurious. The problem likely isn't with the 3rd-party library, but with your usage of it. You have not supplied enough code to give a fully correct answer as it's not clear what fDummy and GetRandom are. If fDummy is being moved into GetRandom, you have a real error here.
The comments have already listed the ways to ignore errors contained within header files: using -isystem (in CMake, imported targets use this by default, otherwise you can manually apply SYSTEM to target_include_directories).
GetRandom and fDummy code can you add it in here?
It is not clear with what you have written.
Also, include directories handle all these warnings in CMAKE.
(yes i meant inclusion as system headers. )
.clang-tidy
...
HeaderFilterRegex: '.*'
...
or
clang-tidy ... --header-filter='.*' ...
From clang-tidy output when analyzing a lot of code:
Suppressed ... warnings (... in non-user code).
Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.

lcov marking lines with function declarations as reachable but not covered

I'm trying to use lcov (v1.13, on OS X, with clang as compiler) to generate code coverage for my test suite and I've hit one annoying problem that I don't know how to solve. There's a few similar questions on SO, but I couldn't find the solution to this one. For some reason, function/member declarations are marked as reachable but not executed, kind of like in the example below (this is inline method definition in a header):
This renders line coverage metrics useless, so I was hoping there's a way to fix it without marking each declaration as LCOV_EXCL_LINE.
Compiler flags used are pretty standard:
-g -O0 -fno-inline -ftest-coverage -fprofile-arcs -fno-elide-constructors
What's strange is that method definitions in source files are also marked as red, although the bodies are not, e.g.:
// header.h
class Foo {
void bar(); // ignored, marked as unreachable
}
// header.cpp
void Foo::bar() { // marked as red (reachable / not executed)
do_something(); // marked as covered
}
If it's of any importance, the source files are part of a static library that's statically linked to the test harness in CMake.
Answering my own question:
Apparently, lcov -i (initial capture) assumes that starting lines of functions are instrumented, whereas with LLVM they are actually not (whereas with GCC where they are). There is an upstream GitHub issue (linux-test-project/lcov#30) documenting this in more detail.
Until this is fixed upstream in lcov, I've posted a simple workaround -- a Python script that removes function starting lines from base coverage file, which should "fix" it, at least temporarily.

Two GCC compiles for same input, two different codes generated (second one wrong)

I am having a strange issue with GCC (4.6.4, Ubuntu 12.04) sometimes, I am using it to compile a huge project (hundreds of files and hundreds of thousands of lines of code), but I recently spotted something. After certain compiles (seems to happen randomly), I get a specific piece of code compiled differently and erroneously, causing undefined behavior in my code:
class someDerivedClass : public someBaseClass
{
public:
struct anotherDerived : public anoterBaseClass
{
void SomeMethod()
{
someMember->someSetter(2);
}
}
}
Where "someSetter" is defined as:
void someSetter(varType varName) { someOtherMember = varName; }
Normally, SomeMethod() gets compiled to:
00000000019fd910 mov 0x20(%rdi),%rax
00000000019fd914 movl $0x2,0x278c(%rax)
00000000019fd91e retq
But sometimes it gets (wrongfully) compiled to:
000000000196e4ee mov 0x20(%rdi),%rax
000000000196e4f2 movl $0x2,0x27d4(%rax)
000000000196e4fc retq
The setter seems to get inlined, probably because of compile flags -O2:
-std=c++11 -m64 -O2 -ggdb3 -pipe -Wliteral-suffix -fpermissive -fno-fast-math -fno-strength-reduce -fno-delete-null-pointer-checks -fno-strict-aliasing
but that's not the issue. The real issue is the offset of the member someOtherMember, 0x278c is correct (first case) but 0x27d4 is incorrect (second case) and this obviously ends up modifying a totally different member of the class. Why is this happening? What am I missing? (also, I don't know what other relevant info I can post, so ask). Please keep in mind that this happens when compiling the project again (either full recompile or just compiling modified files only), without modifying the affected file (or files with the used classes). For example, just adding a simple printf() somewhere in a totally unrelated file might trigger this behavior or make it go away when it happens.
Should I simply blame this on the -O2? I can't reproduce it without optimization flag because this happens totally random.
I am using make -j 8, this happens even after cleaning build folder, but doesn't necessarily happen only after doing that
As stated in the comments, you probably have something that conditions the definition of your class differently in the various .cpp, for example a #pragma pack or something like that before the inclusion of your .h; when the linker has to choose, it may choose non-deterministically (since it expects all the definitions to be the same).
To narrow your search for the root of the problem, I would do something like this:
compile your whole project with debug symbols (-g);
use gdb to determine what is the offset of the "problematic" field according to each module
once you find where you have different values, you may use gcc -E to expand all the preprocessor stuff and look for your problem.
As an aid for step 2, you can use this bash one-liner (to be run in the directory where are the object files):
for i in ./*.o; do echo -n "$i: "; gdb -batch -q "$i" -ex "print &((YourClass*)0)->yourField"; done

Passing parameter to Makefile to change compiled code

I'm new to make. I am working on a C++ shared library, and I want it to have the option to compile with or without support for a certain feature (block of code). In other words, how do I enable the user to choose whether or not to compile the library with that feature by (maybe) passing a parameter to the make command?
For example, I need the user to be able to do this:
make --with-feature-x
How do I do this? Do I need to write a configure file for example? Or can I do this directly within my Makefile?
I believe the following way should work. You define an environment variable when running make. In the Makefile, you check the status of the environment variable. Depending on the status, you define the options that will be passed to g++ when compiling the code. g++ Uses the options in the preprocessing phase to decide what to include in the file (e.g. source.cpp).
The command
make FEATURE=1
Makefile
ifeq ($(FEATURE), 1) #at this point, the makefile checks if FEATURE is enabled
OPTS = -DINCLUDE_FEATURE #variable passed to g++
endif
object:
g++ $(OPTS) source.cpp -o executable //OPTS may contain -DINCLUDE_FEATURE
source.cpp
#ifdef INCLUDE_FEATURE
#include feature.h
//functions that get compiled when feature is enabled
void FeatureFunction1() {
//blah
}
void FeatureFunction2() {
//blah
}
#endif
To check if FEATURE is passed in or not (as any value):
ifdef FEATURE
#do something based on it
else
# feature is not defined. Maybe set it to default value
FEATURE=0
endif

How to remove unused C/C++ symbols with GCC and ld?

I need to optimize the size of my executable severely (ARM development) and
I noticed that in my current build scheme (gcc + ld) unused symbols are not getting stripped.
The usage of the arm-strip --strip-unneeded for the resulting executables / libraries doesn't change the output size of the executable (I have no idea why, maybe it simply can't).
What would be the way (if it exists) to modify my building pipeline, so that the unused symbols are stripped from the resulting file?
I wouldn't even think of this, but my current embedded environment isn't very "powerful" and
saving even 500K out of 2M results in a very nice loading performance boost.
Update:
Unfortunately the current gcc version I use doesn't have the -dead-strip option and the -ffunction-sections... + --gc-sections for ld doesn't give any significant difference for the resulting output.
I'm shocked that this even became a problem, because I was sure that gcc + ld should automatically strip unused symbols (why do they even have to keep them?).
For GCC, this is accomplished in two stages:
First compile the data but tell the compiler to separate the code into separate sections within the translation unit. This will be done for functions, classes, and external variables by using the following two compiler flags:
-fdata-sections -ffunction-sections
Link the translation units together using the linker optimization flag (this causes the linker to discard unreferenced sections):
-Wl,--gc-sections
So if you had one file called test.cpp that had two functions declared in it, but one of them was unused, you could omit the unused one with the following command to gcc(g++):
gcc -Os -fdata-sections -ffunction-sections test.cpp -o test -Wl,--gc-sections
(Note that -Os is an additional compiler flag that tells GCC to optimize for size)
If this thread is to be believed, you need to supply the -ffunction-sections and -fdata-sections to gcc, which will put each function and data object in its own section. Then you give and --gc-sections to GNU ld to remove the unused sections.
You'll want to check your docs for your version of gcc & ld:
However for me (OS X gcc 4.0.1) I find these for ld
-dead_strip
Remove functions and data that are unreachable by the entry point or exported symbols.
-dead_strip_dylibs
Remove dylibs that are unreachable by the entry point or exported symbols. That is, suppresses the generation of load command commands for dylibs which supplied no symbols during the link. This option should not be used when linking against a dylib which is required at runtime for some indirect reason such as the dylib has an important initializer.
And this helpful option
-why_live symbol_name
Logs a chain of references to symbol_name. Only applicable with -dead_strip. It can help debug why something that you think should be dead strip removed is not removed.
There's also a note in the gcc/g++ man that certain kinds of dead code elimination are only performed if optimization is enabled when compiling.
While these options/conditions may not hold for your compiler, I suggest you look for something similar in your docs.
Programming habits could help too; e.g. add static to functions that are not accessed outside a specific file; use shorter names for symbols (can help a bit, likely not too much); use const char x[] where possible; ... this paper, though it talks about dynamic shared objects, can contain suggestions that, if followed, can help to make your final binary output size smaller (if your target is ELF).
The answer is -flto. You have to pass it to both your compilation and link steps, otherwise it doesn't do anything.
It actually works very well - reduced the size of a microcontroller program I wrote to less than 50% of its previous size!
Unfortunately it did seem a bit buggy - I had instances of things not being built correctly. It may have been due to the build system I'm using (QBS; it's very new), but in any case I'd recommend you only enable it for your final build if possible, and test that build thoroughly.
While not strictly about symbols, if going for size - always compile with -Os and -s flags. -Os optimizes the resulting code for minimum executable size and -s removes the symbol table and relocation information from the executable.
Sometimes - if small size is desired - playing around with different optimization flags may - or may not - have significance. For example toggling -ffast-math and/or -fomit-frame-pointer may at times save you even dozens of bytes.
It seems to me that the answer provided by Nemo is the correct one. If those instructions do not work, the issue may be related to the version of gcc/ld you're using, as an exercise I compiled an example program using instructions detailed here
#include <stdio.h>
void deadcode() { printf("This is d dead codez\n"); }
int main(void) { printf("This is main\n"); return 0 ; }
Then I compiled the code using progressively more aggressive dead-code removal switches:
gcc -Os test.c -o test.elf
gcc -Os -fdata-sections -ffunction-sections test.c -o test.elf -Wl,--gc-sections
gcc -Os -fdata-sections -ffunction-sections test.c -o test.elf -Wl,--gc-sections -Wl,--strip-all
These compilation and linking parameters produced executables of size 8457, 8164 and 6160 bytes, respectively, the most substantial contribution coming from the 'strip-all' declaration. If you cannot produce similar reductions on your platform,then maybe your version of gcc does not support this functionality. I'm using gcc(4.5.2-8ubuntu4), ld(2.21.0.20110327) on Linux Mint 2.6.38-8-generic x86_64
strip --strip-unneeded only operates on the symbol table of your executable. It doesn't actually remove any executable code.
The standard libraries achieve the result you're after by splitting all of their functions into seperate object files, which are combined using ar. If you then link the resultant archive as a library (ie. give the option -l your_library to ld) then ld will only include the object files, and therefore the symbols, that are actually used.
You may also find some of the responses to this similar question of use.
I don't know if this will help with your current predicament as this is a recent feature, but you can specify the visibility of symbols in a global manner. Passing -fvisibility=hidden -fvisibility-inlines-hidden at compilation can help the linker to later get rid of unneeded symbols. If you're producing an executable (as opposed to a shared library) there's nothing more to do.
More information (and a fine-grained approach for e.g. libraries) is available on the GCC wiki.
From the GCC 4.2.1 manual, section -fwhole-program:
Assume that the current compilation unit represents whole program being compiled. All public functions and variables with the exception of main and those merged by attribute externally_visible become static functions and in a affect gets more aggressively optimized by interprocedural optimizers. While this option is equivalent to proper use of static keyword for programs consisting of single file, in combination with option --combine this flag can be used to compile most of smaller scale C programs since the functions and variables become local for the whole combined compilation unit, not for the single source file itself.
You can use strip binary on object file(eg. executable) to strip all symbols from it.
Note: it changes file itself and don't create copy.