Skip to content

Commit 14ba827

Browse files
committed
Add Bloaty McBloatface binary size analyzer
* Add Bloaty.cmake module with comprehensive binary analysis targets * Create per-executable analysis targets and global target * Support CSV reports, baselines, and specialized template analysis * Disable by default since it's not available on all systems * Update AI_GUIDELINES.md with Bloaty usage instructions * Add Bloaty to the list of optional tools in guidelines This helps developers identify binary size issues like template bloat and large static data, which is valuable for performance optimization and embedded systems development.
1 parent 958952e commit 14ba827

File tree

4 files changed

+182
-0
lines changed

4 files changed

+182
-0
lines changed

AI_GUIDELINES.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ This project is designed to fail configuration if required tools are missing. Th
141141
- lizard: Code complexity analyzer
142142
- ccache: Compilation cache tool
143143
- include-what-you-use: Header dependency analyzer
144+
- bloaty: Binary size analyzer (optional, disabled by default)
144145

145146
Remember, the project's guardrails exist for a reason. Help the user install and use the required tools rather than circumventing them.
146147

@@ -231,6 +232,37 @@ cmake --build build --target lizard_html
231232
cmake --build build --target lizard_xml
232233
```
233234

235+
### Binary Size Analysis with Bloaty McBloatface
236+
237+
The project includes optional support for Bloaty McBloatface, a binary size analyzer. This tool helps identify what's contributing to executable size, which is valuable for embedded systems and performance optimization.
238+
239+
Note: Bloaty is disabled by default as it may not be installed on all systems. Enable with `-D<project_name>_ENABLE_BLOATY=ON`.
240+
241+
When Bloaty is enabled, it provides several analysis targets for each executable:
242+
243+
```bash
244+
# Basic size analysis for a specific target (e.g., "intro")
245+
cmake --build build --target bloaty_intro
246+
247+
# Generate CSV report
248+
cmake --build build --target bloaty_intro_csv
249+
250+
# Store current binary as a baseline for comparisons
251+
cmake --build build --target bloaty_intro_store
252+
253+
# Analyze template usage (particularly useful for C++ binary bloat)
254+
cmake --build build --target bloaty_intro_templates
255+
256+
# Run analysis on all executable targets
257+
cmake --build build --target bloaty_all
258+
```
259+
260+
When addressing binary size issues:
261+
1. Look for excessive template instantiations
262+
2. Check for large static data or string literals
263+
3. Consider enabling Link Time Optimization (LTO)
264+
4. Evaluate if all included functionality is necessary
265+
234266
### Compiler Warning Configuration
235267

236268
Each supported compiler (GCC, Clang, MSVC) has specific warning flags enabled:

ProjectOptions.cmake

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ macro(myproject_setup_options)
7979
option(myproject_ENABLE_CLANG_TIDY "Enable clang-tidy" OFF)
8080
option(myproject_ENABLE_CPPCHECK "Enable cpp-check analysis" OFF)
8181
option(myproject_ENABLE_LIZARD "Enable Lizard complexity analysis" OFF)
82+
option(myproject_ENABLE_BLOATY "Enable Bloaty McBloatface binary size analysis" OFF)
8283
option(myproject_ENABLE_PCH "Enable precompiled headers" OFF)
8384
option(myproject_ENABLE_CACHE "Enable ccache" OFF)
8485
else()
@@ -94,6 +95,7 @@ macro(myproject_setup_options)
9495
option(myproject_ENABLE_CLANG_TIDY "Enable clang-tidy" ON)
9596
option(myproject_ENABLE_CPPCHECK "Enable cpp-check analysis" ON)
9697
option(myproject_ENABLE_LIZARD "Enable Lizard complexity analysis" ON)
98+
option(myproject_ENABLE_BLOATY "Enable Bloaty McBloatface binary size analysis" OFF)
9799
option(myproject_ENABLE_PCH "Enable precompiled headers" OFF)
98100
option(myproject_ENABLE_CACHE "Enable ccache" ON)
99101
endif()
@@ -112,6 +114,7 @@ macro(myproject_setup_options)
112114
myproject_ENABLE_CLANG_TIDY
113115
myproject_ENABLE_CPPCHECK
114116
myproject_ENABLE_LIZARD
117+
myproject_ENABLE_BLOATY
115118
myproject_ENABLE_COVERAGE
116119
myproject_ENABLE_PCH
117120
myproject_ENABLE_CACHE)
@@ -212,6 +215,10 @@ macro(myproject_local_options)
212215
if(myproject_ENABLE_LIZARD)
213216
myproject_enable_lizard(${myproject_WARNINGS_AS_ERRORS})
214217
endif()
218+
219+
if(myproject_ENABLE_BLOATY)
220+
myproject_enable_bloaty()
221+
endif()
215222

216223
if(myproject_ENABLE_COVERAGE)
217224
include(cmake/Tests.cmake)

cmake/Bloaty.cmake

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
# Bloaty McBloatface - A binary size analyzer
2+
# This module enables Bloaty for analyzing executable and library sizes
3+
4+
function(myproject_setup_bloaty TARGET_NAME)
5+
find_program(BLOATY bloaty)
6+
if(BLOATY)
7+
# Define output directory
8+
set(BLOATY_OUTPUT_DIR "${CMAKE_BINARY_DIR}/bloaty_reports")
9+
file(MAKE_DIRECTORY ${BLOATY_OUTPUT_DIR})
10+
11+
# Default report sections
12+
set(BLOATY_SECTIONS "sections,symbols,compileunits")
13+
14+
# Create custom target for basic size analysis
15+
add_custom_target(
16+
bloaty_${TARGET_NAME}
17+
COMMAND ${BLOATY} $<TARGET_FILE:${TARGET_NAME}> -d ${BLOATY_SECTIONS} --domain=vm
18+
DEPENDS ${TARGET_NAME}
19+
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
20+
COMMENT "Running Bloaty size analysis on ${TARGET_NAME}..."
21+
)
22+
23+
# Create custom target for CSV report
24+
add_custom_target(
25+
bloaty_${TARGET_NAME}_csv
26+
COMMAND ${BLOATY} $<TARGET_FILE:${TARGET_NAME}> -d ${BLOATY_SECTIONS} --csv > "${BLOATY_OUTPUT_DIR}/${TARGET_NAME}_size.csv"
27+
DEPENDS ${TARGET_NAME}
28+
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
29+
COMMENT "Generating Bloaty CSV report for ${TARGET_NAME}..."
30+
)
31+
32+
# Create custom target for diff against a baseline
33+
# This target needs to be manually called with a baseline file
34+
add_custom_target(
35+
bloaty_${TARGET_NAME}_diff
36+
COMMAND ${CMAKE_COMMAND} -E echo "Run with: cmake --build build --target bloaty_${TARGET_NAME}_diff -- --baseline=/path/to/baseline"
37+
COMMENT "To compare against a baseline, provide --baseline argument"
38+
)
39+
40+
# Add custom command to track binary size changes over time
41+
add_custom_target(
42+
bloaty_${TARGET_NAME}_store
43+
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${TARGET_NAME}> "${BLOATY_OUTPUT_DIR}/${TARGET_NAME}_baseline_$$(date +%Y%m%d%H%M%S)"
44+
COMMAND ${CMAKE_COMMAND} -E echo "Stored baseline at ${BLOATY_OUTPUT_DIR}/${TARGET_NAME}_baseline_$$(date +%Y%m%d%H%M%S)"
45+
DEPENDS ${TARGET_NAME}
46+
COMMENT "Storing current binary as baseline for ${TARGET_NAME}..."
47+
)
48+
49+
# Create custom target for template analysis (C++ specific)
50+
add_custom_target(
51+
bloaty_${TARGET_NAME}_templates
52+
COMMAND ${BLOATY} $<TARGET_FILE:${TARGET_NAME}> -d template_params,symbols
53+
DEPENDS ${TARGET_NAME}
54+
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
55+
COMMENT "Analyzing template usage in ${TARGET_NAME}..."
56+
)
57+
58+
message(STATUS "Bloaty McBloatface targets created for ${TARGET_NAME}")
59+
else()
60+
message(${myproject_WARNING_TYPE} "Bloaty McBloatface requested but executable not found. Install with 'apt install bloaty' or from https://github.com/google/bloaty")
61+
endif()
62+
endfunction()
63+
64+
# Function to add bloaty analysis to all executable targets
65+
function(myproject_enable_bloaty)
66+
find_program(BLOATY bloaty)
67+
if(BLOATY)
68+
# Get all executable targets
69+
get_all_executable_targets(ALL_TARGETS)
70+
71+
# Create global target that will depend on all individual targets
72+
add_custom_target(bloaty_all)
73+
74+
# Create individual bloaty targets for each executable
75+
foreach(TARGET_NAME ${ALL_TARGETS})
76+
myproject_setup_bloaty(${TARGET_NAME})
77+
add_dependencies(bloaty_all bloaty_${TARGET_NAME})
78+
endforeach()
79+
80+
message(STATUS "Bloaty McBloatface enabled for all executable targets")
81+
else()
82+
message(${myproject_WARNING_TYPE} "Bloaty McBloatface requested but executable not found. Install with 'apt install bloaty' or from https://github.com/google/bloaty")
83+
endif()
84+
endfunction()
85+
86+
# Helper function to get all executable targets
87+
function(get_all_executable_targets RESULT)
88+
set(TARGETS)
89+
90+
# Recursive function to get all targets
91+
get_property(TARGETS_IN_DIR DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" PROPERTY BUILDSYSTEM_TARGETS)
92+
93+
foreach(TARGET_NAME ${TARGETS_IN_DIR})
94+
get_target_property(TARGET_TYPE ${TARGET_NAME} TYPE)
95+
if(TARGET_TYPE STREQUAL "EXECUTABLE")
96+
list(APPEND TARGETS ${TARGET_NAME})
97+
endif()
98+
endforeach()
99+
100+
# Check subdirectories
101+
get_property(SUBDIRS DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" PROPERTY SUBDIRECTORIES)
102+
foreach(SUBDIR ${SUBDIRS})
103+
get_all_executable_targets_in_dir(${SUBDIR} SUBDIR_TARGETS)
104+
list(APPEND TARGETS ${SUBDIR_TARGETS})
105+
endforeach()
106+
107+
set(${RESULT} ${TARGETS} PARENT_SCOPE)
108+
endfunction()
109+
110+
# Helper function to get targets in a specific directory
111+
function(get_all_executable_targets_in_dir DIR RESULT)
112+
set(TARGETS)
113+
114+
get_property(TARGETS_IN_DIR DIRECTORY "${DIR}" PROPERTY BUILDSYSTEM_TARGETS)
115+
116+
foreach(TARGET_NAME ${TARGETS_IN_DIR})
117+
get_target_property(TARGET_TYPE ${TARGET_NAME} TYPE)
118+
if(TARGET_TYPE STREQUAL "EXECUTABLE")
119+
list(APPEND TARGETS ${TARGET_NAME})
120+
endif()
121+
endforeach()
122+
123+
# Check subdirectories
124+
get_property(SUBDIRS DIRECTORY "${DIR}" PROPERTY SUBDIRECTORIES)
125+
foreach(SUBDIR ${SUBDIRS})
126+
get_all_executable_targets_in_dir(${SUBDIR} SUBDIR_TARGETS)
127+
list(APPEND TARGETS ${SUBDIR_TARGETS})
128+
endforeach()
129+
130+
set(${RESULT} ${TARGETS} PARENT_SCOPE)
131+
endfunction()

cmake/StaticAnalyzers.cmake

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,15 @@ macro(myproject_enable_lizard WARNINGS_AS_ERRORS)
128128
myproject_tool_not_found_warning("lizard")
129129
endif()
130130
endmacro()
131+
132+
# Enable Bloaty McBloatface for binary size analysis
133+
macro(myproject_enable_bloaty)
134+
find_program(BLOATY bloaty)
135+
if(BLOATY)
136+
include(cmake/Bloaty.cmake)
137+
# Function defined in Bloaty.cmake
138+
myproject_enable_bloaty()
139+
else()
140+
myproject_tool_not_found_warning("bloaty")
141+
endif()
142+
endmacro()

0 commit comments

Comments
 (0)