patternMinor
CMake module to make executable as small as possible
Viewed 0 times
cmakeexecutablemodulemakepossiblesmall
Problem
I wrote this .cmake script when I needed to make smallest possible executables. It makes CMake prefer static libraries, and adds custom command to strip and UPX the end result. I used it only with MinGW on Windows with MSYS2.
My questions:
example
example
```
##
# How to use:
# include(ReallySmall.cmake)
#
# prefer_static_libs()
# find_package(STATIC_LIBS)
# restore_preferred_libs()
# find_package(SHARED_LIBS)
#
# add_executable(MY_EXE)
# make_small_executable(MY_EXE)
# target_link_libraries(...)
##
function(add_static_definitions TARGET_NAME)
if(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
set(IS_M
My questions:
- Can this be made more short and readable?
- Are my checks portable enough?
- Any way to handle MSVC?
example
main.c#include
#include
#include
#include
int main()
{
if(!glfwInit())
return EXIT_FAILURE;
GLFWwindow *window = glfwCreateWindow(1024, 768, "Hello World", NULL, NULL);
if(!window)
{
glfwTerminate();
return EXIT_FAILURE;
}
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
glewExperimental = GL_TRUE;
GLenum code = glewInit();
if(code != GLEW_OK)
{
fprintf(stderr, "[GLEW Error](%d): %s\n", code, glewGetErrorString(code));
return EXIT_FAILURE;
}
}example
CMakeLists.txtcmake_minimum_required(VERSION 3.0)
project(staticExe LANGUAGES C)
include(${PROJECT_SOURCE_DIR}/cmake/ReallySmall.cmake)
prefer_static_libs()
find_package(GLEW REQUIRED)
find_package(GLFW3 NAMES glfw glfw3 REQUIRED)
restore_preferred_libs()
find_package(OpenGL REQUIRED)
set(INCLUDE_DIRS ${OPENGL_INCLUDE_DIR} ${GLFW3_INCLUDE_DIR})
set(LIBS GLEW::GLEW ${GLFW3_LIBRARY} ${OPENGL_gl_LIBRARY})
add_executable(${PROJECT_NAME} WIN32 main.c)
make_small_executable(${PROJECT_NAME})
add_static_definitions(${PROJECT_NAME} "GLEW_STATIC")
target_include_directories(${PROJECT_NAME} PUBLIC ${INCLUDE_DIRS})
target_link_libraries(${PROJECT_NAME} ${LIBS})ReallySmall.cmake```
##
# How to use:
# include(ReallySmall.cmake)
#
# prefer_static_libs()
# find_package(STATIC_LIBS)
# restore_preferred_libs()
# find_package(SHARED_LIBS)
#
# add_executable(MY_EXE)
# make_small_executable(MY_EXE)
# target_link_libraries(...)
##
function(add_static_definitions TARGET_NAME)
if(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
set(IS_M
Solution
Here are some ideas about how to reduce the complexity and thereby increase the readability of your module's code:
-
You could merge
-
You could move the post build steps into its own CMake script like
cmake/ReallySmallPostBuild.cmake
cmake/ReallySmall.cmake
-
You could simplify your
cmake/ReallySmall.cmake
Or if you take my recommendation from the top to always prefer static libs, I think you should directly put those definition declarations to
CMakeLists.txt
-
You could merge
prefer_static_libs(), find_package() and restore_preferred_libs() into a single dedicated macro likemacro(rs_find_package)
set(_OLD_FIND_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib" ".a" ".so" ".sl" ".dylib" ".dll.a")
find_package(${ARGN})
set(CMAKE_FIND_LIBRARY_SUFFIXES ${_OLD_FIND_SUFFIXES})
unset(_OLD_FIND_SUFFIXES)
endmacro(rs_find_package)- The simplified version
CMAKE_FIND_LIBRARY_SUFFIXESpreferring static libraries on all platforms is taken fromTest/OutDir/OutDir.cmake
- In your use case I would recommend to prefer static libraries for all configurations to simplify the usage in multi-configuration environments like Visual Studio (otherwise we have to run
find_package()twice)
-
You could move the post build steps into its own CMake script like
cmake/ReallySmallPostBuild.cmake
if(EXECUTE_POST_BUILD)
if (CMAKE_STRIP)
execute_process(COMMAND ${CMAKE_STRIP} -s ${TARGET_FILE})
endif()
if(SELF_PACKER_FOR_EXECUTABLE)
execute_process(COMMAND ${SELF_PACKER_FOR_EXECUTABLE} -9q ${TARGET_FILE})
endif()
endif()cmake/ReallySmall.cmake
...
add_custom_command(
TARGET ${TARGET_NAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND}
-D EXECUTE_POST_BUILD=$
-D TARGET_FILE="$"
-D CMAKE_STRIP="${CMAKE_STRIP}"
-D SELF_PACKER_FOR_EXECUTABLE="${SELF_PACKER_FOR_EXECUTABLE}"
-P ${CMAKE_SOURCE_DIR}/cmake/ReallySmallPostBuild.cmake
)
...- This works also for multi-configuration environments, since the check for "Should I execute post build steps?" is inside the external script
- I've moved your
STRIP_FLAGSandSELF_PACKER_FOR_EXECUTABLE_FLAGSa fixed parameters directly into the external script
-
You could simplify your
add_static_definitions() with generator expressions:cmake/ReallySmall.cmake
...
function(add_static_definitions TARGET_NAME)
target_compile_definitions(${TARGET_NAME} PUBLIC $:${ARGN}>)
endfunction()
...Or if you take my recommendation from the top to always prefer static libs, I think you should directly put those definition declarations to
CMakeLists.txt
...
target_compile_definitions(${PROJECT_NAME} PUBLIC "GLEW_STATIC")
...- I did not see the necessity for the
_SMALL_EXECUTABLEScrosschecks, so they are removed here
Code Snippets
macro(rs_find_package)
set(_OLD_FIND_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib" ".a" ".so" ".sl" ".dylib" ".dll.a")
find_package(${ARGN})
set(CMAKE_FIND_LIBRARY_SUFFIXES ${_OLD_FIND_SUFFIXES})
unset(_OLD_FIND_SUFFIXES)
endmacro(rs_find_package)if(EXECUTE_POST_BUILD)
if (CMAKE_STRIP)
execute_process(COMMAND ${CMAKE_STRIP} -s ${TARGET_FILE})
endif()
if(SELF_PACKER_FOR_EXECUTABLE)
execute_process(COMMAND ${SELF_PACKER_FOR_EXECUTABLE} -9q ${TARGET_FILE})
endif()
endif()...
add_custom_command(
TARGET ${TARGET_NAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND}
-D EXECUTE_POST_BUILD=$<CONFIG:MinSizeRel>
-D TARGET_FILE="$<TARGET_FILE:${TARGET_NAME}>"
-D CMAKE_STRIP="${CMAKE_STRIP}"
-D SELF_PACKER_FOR_EXECUTABLE="${SELF_PACKER_FOR_EXECUTABLE}"
-P ${CMAKE_SOURCE_DIR}/cmake/ReallySmallPostBuild.cmake
)
......
function(add_static_definitions TARGET_NAME)
target_compile_definitions(${TARGET_NAME} PUBLIC $<$<CONFIG:MinSizeRel>:${ARGN}>)
endfunction()
......
target_compile_definitions(${PROJECT_NAME} PUBLIC "GLEW_STATIC")
...Context
StackExchange Code Review Q#103972, answer score: 3
Revisions (0)
No revisions yet.