如何解决如何配置柯南不链接一切可能?
我正在试用柯南软件包管理器,并开始编写一个使用Poco libraries的测试C ++项目。我制作了一个简单的程序,仅使用AES-256-CBC解密字符串。使用Conan和Cmake构建后,生成的二进制文件将近4 MB令我感到非常惊讶。我尝试调整conanfile.txt
和CmakeLists.txt
文件以仅链接必要的库,但是我要么无法编译项目,要么无法减小已编译二进制文件的大小。
我非常确定PCRE,bzip2,sqllite等将链接到我的二进制文件中,因为Poco依赖于它们。我对为什么gcc
不够聪明无法弄清楚我正在调用的Poco代码仅使用少量的OpenSSL代码感到非常困惑。
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 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();
}
我如何构建代码:
#!/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
解决方法
您所做的没有任何问题。 poco
可能有很多依赖性和功能。您可以在CMakeLists.txt中添加message(STATUS "Linkd libraries: " ${CONAN_LIBS})
,然后再次运行cmake来查看使用${CONAN_LIBS}
时当前与之链接的库。
您也可以尝试在CMakeLists.txt
中使用conan_basic_setup(TARGETS)
,而不仅仅是conan_basic_setup()
。如果这样做,则需要将target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS})
更改为target_link_libraries(${PROJECT_NAME} CONAN_PKG::poco)
。这样,您就可以更好地控制与conanfile.txt
中的每个目标链接的CMaksLists.txt
中的哪些库。但是,由于您的conanfile.txt
仅具有poco
作为依赖项,因此不应进行任何更改。
您可以尝试的另一件事是检查柯南的poco
配方是否具有可以设置为包含/排除poco
库部分的任何选项。运行以下命令(假设您的柯南缓存中已经安装了poco/1.10.1
)
conan get poco/1.10.1
这将向您显示柯南正在使用的poco
的完整食谱。我到了
from conans import ConanFile,CMake,tools
from conans.errors import ConanException,ConanInvalidConfiguration
from collections import namedtuple,OrderedDict
import os
class PocoConan(ConanFile):
name = "poco"
url = "https://github.com/conan-io/conan-center-index"
homepage = "https://pocoproject.org"
topics = ("conan","poco","building","networking","server","mobile","embedded")
exports_sources = "CMakeLists.txt","patches/**"
generators = "cmake","cmake_find_package"
settings = "os","arch","compiler","build_type"
license = "BSL-1.0"
description = "Modern,powerful open source C++ class libraries for building network- and internet-based " \
"applications that run on desktop,server,mobile and embedded systems."
options = {
"shared": [True,False],"fPIC": [True,}
default_options = {
"shared": False,"fPIC": True,}
_PocoComponent = namedtuple("_PocoComponent",("option","default_option","dependencies","is_lib"))
_poco_component_tree = {
"mod_poco": _PocoComponent("enable_apacheconnector",False,("PocoUtil","PocoNet",),False),# also external apr and apr-util
"PocoCppParser": _PocoComponent("enable_cppparser",("PocoFoundation",# "PocoCppUnit": _PocoComponent("enable_cppunit",False)),"PocoCrypto": _PocoComponent("enable_crypto",True,True),# also external openssl
"PocoData": _PocoComponent("enable_data","PocoDataMySQL": _PocoComponent("enable_data_mysql",("PocoData","PocoDataODBC": _PocoComponent("enable_data_odbc","PocoDataPostgreSQL": _PocoComponent("enable_data_postgresql",# also external postgresql
"PocoDataSQLite": _PocoComponent("enable_data_sqlite",# also external sqlite3
"PocoEncodings": _PocoComponent("enable_encodings",# "PocoEncodingsCompiler": _PocoComponent("enable_encodingscompiler",("PocoNet","PocoUtil","PocoFoundation": _PocoComponent(None,"PocoFoundation",(),"PocoJSON": _PocoComponent("enable_json","PocoJWT": _PocoComponent("enable_jwt",("PocoJSON","PocoCrypto","PocoMongoDB": _PocoComponent("enable_mongodb","PocoNet": _PocoComponent("enable_net","PocoNetSSL": _PocoComponent("enable_netssl",("PocoCrypto",# also external openssl
"PocoNetSSLWin": _PocoComponent("enable_netssl_win","PocoPDF": _PocoComponent("enable_pdf",("PocoXML","PocoPageCompiler": _PocoComponent("enable_pagecompiler","PocoFile2Page": _PocoComponent("enable_pagecompiler_file2page","PocoXML","PocoJSON","PocoPocoDoc": _PocoComponent("enable_pocodoc","PocoCppParser","PocoRedis": _PocoComponent("enable_redis","PocoSevenZip": _PocoComponent("enable_sevenzip","PocoUtil": _PocoComponent("enable_util","PocoXML": _PocoComponent("enable_xml","PocoZip": _PocoComponent("enable_zip",}
for comp in _poco_component_tree.values():
if comp.option:
options[comp.option] = [True,False]
default_options[comp.option] = comp.default_option
del comp
@property
def _poco_ordered_components(self):
remaining_components = dict((compname,set(compopts.dependencies)) for compname,compopts in self._poco_component_tree.items())
ordered_components = []
while remaining_components:
components_no_deps = set(compname for compname,compopts in remaining_components.items() if not compopts)
if not components_no_deps:
raise ConanException("The poco dependency tree is invalid and contains a cycle")
for c in components_no_deps:
remaining_components.pop(c)
ordered_components.extend(components_no_deps)
for rname in remaining_components.keys():
remaining_components[rname] = remaining_components[rname].difference(components_no_deps)
ordered_components.reverse()
return ordered_components
_cmake = None
@property
def _source_subfolder(self):
return "source_subfolder"
@property
def _build_subfolder(self):
return "build_subfolder"
def source(self):
tools.get(**self.conan_data["sources"][self.version])
extracted_folder = "poco-poco-{}-release".format(self.version)
os.rename(extracted_folder,self._source_subfolder)
def config_options(self):
if self.settings.os == "Windows":
del self.options.fPIC
else:
del self.options.enable_netssl_win
if tools.Version(self.version) < "1.9":
del self.options.enable_encodings
if tools.Version(self.version) < "1.10":
del self.options.enable_data_postgresql
del self.options.enable_jwt
def configure(self):
if self.options.enable_apacheconnector:
raise ConanInvalidConfiguration("Apache connector not supported: https://github.com/pocoproject/poco/issues/1764")
if self.options.enable_data_mysql:
raise ConanInvalidConfiguration("MySQL not supported yet,open an issue here please: %s" % self.url)
if self.options.get_safe("enable_data_postgresql",False):
raise ConanInvalidConfiguration("PostgreSQL not supported yet,open an issue here please: %s" % self.url)
for compopt in self._poco_component_tree.values():
if not compopt.option:
continue
if self.options.get_safe(compopt.option,False):
for compdep in compopt.dependencies:
if not self._poco_component_tree[compdep].option:
continue
if not self.options.get_safe(self._poco_component_tree[compdep].option,False):
raise ConanInvalidConfiguration("option {} requires also option {}".format(compopt.option,self._poco_component_tree[compdep].option))
def requirements(self):
self.requires("pcre/8.41")
self.requires("zlib/1.2.11")
if self.options.enable_xml:
self.requires("expat/2.2.9")
if self.options.enable_data_sqlite:
self.requires("sqlite3/3.31.1")
if self.options.enable_apacheconnector:
self.requires("apr/1.7.0")
self.requires("apr-util/1.6.1")
raise ConanInvalidConfiguration("apache2 is not (yet) available on CCI")
self.requires("apache2/x.y.z")
if self.options.enable_netssl or \
self.options.enable_crypto or \
self.options.get_safe("enable_jwt",False):
self.requires("openssl/1.1.1g")
def _patch_sources(self):
for patch in self.conan_data.get("patches",{}).get(self.version,[]):
tools.patch(**patch)
def _configure_cmake(self):
if self._cmake:
return self._cmake
self._cmake = CMake(self)
if tools.Version(self.version) < "1.10.1":
self._cmake.definitions["POCO_STATIC"] = not self.options.shared
for comp in self._poco_component_tree.values():
if not comp.option:
continue
self._cmake.definitions[comp.option.upper()] = self.options.get_safe(comp.option,False)
self._cmake.definitions["POCO_UNBUNDLED"] = True
self._cmake.definitions["CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP"] = True
if self.settings.os == "Windows" and self.settings.compiler == "Visual Studio": # MT or MTd
self._cmake.definitions["POCO_MT"] = "ON" if "MT" in str(self.settings.compiler.runtime) else "OFF"
self.output.info(self._cmake.definitions)
# On Windows,Poco needs a message (MC) compiler.
with tools.vcvars(self.settings) if self.settings.compiler == "Visual Studio" else tools.no_op():
self._cmake.configure(build_dir=self._build_subfolder)
return self._cmake
def build(self):
if self.options.enable_data_sqlite:
if self.options["sqlite3"].threadsafe == 0:
raise ConanInvalidConfiguration("sqlite3 must be built with threadsafe enabled")
self._patch_sources()
cmake = self._configure_cmake()
cmake.build()
def package(self):
self.copy("LICENSE",dst="licenses",src=self._source_subfolder)
cmake = self._configure_cmake()
cmake.install()
tools.rmdir(os.path.join(self.package_folder,"lib","cmake"))
tools.rmdir(os.path.join(self.package_folder,"cmake"))
@property
def _ordered_libs(self):
libs = []
for compname in self._poco_ordered_components:
comp_options = self._poco_component_tree[compname]
if comp_options.is_lib:
if not comp_options.option:
libs.append(compname)
elif self.options.get_safe(comp_options.option,False):
libs.append(compname)
return libs
def package_info(self):
suffix = str(self.settings.compiler.runtime).lower() \
if self.settings.compiler == "Visual Studio" and not self.options.shared \
else ("d" if self.settings.build_type == "Debug" else "")
self.cpp_info.libs = list("{}{}".format(lib,suffix) for lib in self._ordered_libs)
if self.settings.os == "Linux":
self.cpp_info.system_libs.extend(["pthread","dl","rt"])
if self.settings.compiler == "Visual Studio":
self.cpp_info.defines.append("POCO_NO_AUTOMATIC_LIBS")
if not self.options.shared:
self.cpp_info.defines.append("POCO_STATIC=ON")
if self.settings.compiler == "Visual Studio":
self.cpp_info.system_libs.extend(["ws2_32","iphlpapi","crypt32"])
self.cpp_info.names["cmake_find_package"] = "Poco"
self.cpp_info.names["cmake_find_package_multi"] = "Poco"
您要查看的是options
和default_options
中的食谱。
据我所知,除了查看像这样的实际食谱源代码外,没有办法查询食谱提供的选项以及它们的作用。
似乎poco食谱从此_poco_component_tree
字典中添加了很多选项。您要检查的是名称为enable_something
且值为True
的选项。由于这些是作为选项添加的,因此这意味着客户端(您正在运行conan)可以在运行conan install
时控制它们。例如,请尝试下面的命令(您可以添加多个-o poco:something
来设置多个选项)
conan install .. -o poco:enable_data_sqlite=False
我们在食谱的requirements
方法中看到,只有当enable_data_sqlite
为True
时,柯南才会添加“ sqlite3 / 3.31.1”是poco依赖项。这意味着,如果将enable_data_sqlite
设置为False
,则根本不应该包含它,并且二进制文件应该变小。
由于柯南(以及poco开发人员或创建poco秘诀的人)希望尽可能轻松地使用conan安装poco,因此默认情况下包含poco的最常见部分是有意义的。使用柯南选项禁用它的某些部分是您可以控制它的方法。您将不得不尝试这些选项中的一些选项,以查看得到的结果。如果禁用了您真正需要的功能,则在编译和/或链接实际代码时会出错。
,请仔细查看Poco/Config.h
,因为其中有几个宏可让您禁用Poco的某些部分。这些宏可以帮助您轻松地删除不需要的二进制文件(例如:XML,JSON,INI配置文件,也为POCO_NO_AUTOMATIC_LIBS
)。我希望这些和其他可以减少目标文件的大小。
我知道这已经有一段时间了,但是Poco已被用于在非常小型“面板”上运行Web服务器。参见https://pocoproject.org/blog/?p=193。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。