I'm trying out the Conan package manager, and started writing a test C++ project that uses the Poco libraries. I produced a simple program that just decrypts a string using AES-256-CBC. I was extremely surprised to find the generated binary was almost 4 MB after building with Conan and Cmake. I tried tweaking the conanfile.txt
and CmakeLists.txt
files to only link the necessary libraries, but I either couldn't get the project to compile, or couldn't reduce the size of the compiled binary.
I'm pretty sure that PCRE, bzip2, SQLlite and more are getting linked in to my binary, as Poco depends on them. I'm just very confused as to why gcc
isn't smart enough to figure out that the Poco code I'm calling is only using a small bit of OpenSSL code.
How can I only compile in/link what I need to, and keep my binary to a reasonable size?
conanfile.txt:
[requires]
poco/1.10.1
[generators]
cmake
CmakeLists.txt:
cmake_minimum_required(VERSION 3.7...3.18)
if(${CMAKE_VERSION} VERSION_LESS 3.12)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
endif()
project(main)
add_definitions("-std=c++17")
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS})
main.cpp:
#include <cstdlib>
#include <iostream>
#include <sstream>
#include "Poco/Base64Decoder.h"
#include "Poco/Crypto/Cipher.h"
#include "Poco/Crypto/CipherFactory.h"
#include "Poco/Crypto/CipherKey.h"
#include "Poco/DigestStream.h"
#include "Poco/SHA2Engine.h"
std::string sha512(std::string value);
std::string aesDecrypt(const std::string ciphertext, const std::string key, const std::string iv);
std::string getEnvVar(const std::string key);
std::string base64Decode(const std::string encoded);
int main(int argc, char** argv) {
std::string enc = "Ug7R5BQIosmn1yPeawSUIzY8N9wzASmI/w0Wz/xX7Yw=";
std::cout << aesDecrypt(enc, "admin", "7K/OkQIrl4rqUk8/1h+uuQ==") << "\n";
std::cout << sha512("Hello there") << "\n";
std::cout << getEnvVar("USER") << "\n";
return 0;
}
std::string aesDecrypt(const std::string ciphertext, const std::string key, const std::string iv) {
auto keyHash = sha512(key);
Poco::Crypto::Cipher::ByteVec keyBytes{keyHash.begin(), keyHash.end()};
auto rawIV = base64Decode(iv);
Poco::Crypto::Cipher::ByteVec ivBytes{rawIV.begin(), rawIV.end()};
auto &factory = Poco::Crypto::CipherFactory::defaultFactory();
auto pCipher = factory.createCipher(Poco::Crypto::CipherKey("aes-256-cbc", keyBytes, ivBytes));
return pCipher->decryptString(ciphertext, Poco::Crypto::Cipher::ENC_BASE64);
}
std::string sha512(const std::string value) {
Poco::SHA2Engine sha256(Poco::SHA2Engine::SHA_512);
Poco::DigestOutputStream ds(sha256);
ds << value;
ds.close();
return Poco::DigestEngine::digestToHex(sha256.digest());
}
std::string getEnvVar(const std::string key) {
char * val = getenv(key.c_str());
return val == NULL ? std::string("") : std::string(val);
}
std::string base64Decode(const std::string encoded) {
std::istringstream istr(encoded);
std::ostringstream ostr;
Poco::Base64Decoder b64in(istr);
copy(std::istreambuf_iterator<char>(b64in),
std::istreambuf_iterator<char>(),
std::ostreambuf_iterator<char>(ostr));
return ostr.str();
}
How I build the code:
#!/bin/bash
set -e
set -x
rm -rf build
mkdir build
pushd build
conan install ..
cmake .. -DCMAKE_BUILD_TYPE=Release
cmake --build .
ls -lah bin/main
bin/main
Take a careful look at
Poco/Config.h
as there a several macros that allow you to disable certain parts of Poco. These macros exist to help you easily strip down your binaries if you don't want them (ex: XML, JSON, INI config files, alsoPOCO_NO_AUTOMATIC_LIBS
). I would expect these and others to reduce your object file size.I know this was quite a while ago, but Poco has been used to run a web server on a very small "board". See https://pocoproject.org/blog/?p=193.