在CMake中创建共享库时,如何检查或忽略丢失的DLL?

时间:2018-10-30 23:57:20

标签: c++ dll cmake shared-libraries cross-platform

问题:我想忽略“找不到dll”错误,并继续执行不依赖该库的代码。

我知道这是很多问题,但是没有关于共享库的权威指南,而且混乱的谈话令人困惑。我收集到了CMake知道的三种类型的库:

  • 静态:在编译时链接到可执行文件。
  • 共享的:UNIX:可在Windows上随时加载:WINDOWS:需要在编译时链接符号STATIC库,以映射出DLL。
  • 模块:运行时加载的共享库,我仍在理解中。

我正在使用CMake'GenerateExportHeader'来简化共享库的制作。这可行。我什至可以对那些库进行版本控制,以即时更改它们。但是,我在弄清楚麻烦的是如何检查并在找不到dll的情况下忽略该错误:

“由于找不到xxx.dll,因此无法继续执行代码。重新安装程序可能会解决此问题。”

我尝试将try / catch块放入包含/对象创建中。 Google foo没有找到任何东西。

我已经研究了“ MODULE”类型的共享库,但我希望避免出现“ __declspec”和可加载库的混乱情况。

CMake的'GenerateExportHeader'非常好,如果不手动导出符号就无法实现我要的内容,但是我想我可能会问问大师。

所以...。代码:

CMakeLists.txt:

...
set(BUILD_SHARED_LIBS ON)
set(BUILD_TYPE SHARED)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
include(GenerateExportHeader)

...

# Create the library.
add_library(${NAME} ${BUILD_TYPE}
    ${SOURCES}
)

# Visual Studio Source Tree and filters.
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCES})
set_property(TARGET ${NAME} PROPERTY FOLDER "${NAME}")

if(BUILD_SHARED_LIBS)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
GENERATE_EXPORT_HEADER(${NAME}
    BASE_NAME ${NAME}
    EXPORT_MACRO_NAME ${NAME}_EXPORTS
    EXPORT_FILE_NAME ${NAME}_EXPORTS.h
    STATIC_DEFINE SHARED_EXPORTS_BUILT_AS_STATIC)
endif(BUILD_SHARED_LIBS)

target_include_directories(${NAME} PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/public>
    $<INSTALL_INTERFACE:public>
    PRIVATE private
)

# Link to other libraries.
target_link_libraries(${NAME}
    ${EXAMPLE_LIBRARY}
)

# 'make install' to correct locations.
install(TARGETS ${NAME} EXPORT ${NAME}Config
    ARCHIVE DESTINATION lib
    LIBRARY DESTINATION lib
    RUNTIME DESTINATION bin) # For windows.
install(DIRECTORY public/ DESTINATION include)
# 'public'/ project, 'include' for install.

# Importable from the install directory.
# Configs in per-project dir.
install (EXPORT ${NAME}Config DESTINATION share/${NAME}/cmake)
# Importable from the build directory.
export(TARGETS ${NAME} FILE ${NAME}Config.cmake)

# Library Testing/Future unit tests.
set(TESTING_PRIVATE
    Tests/Main.cpp
)
set(TESTING_PUBLIC

)
set(TESTING_COLLECTIVE
    ${TESTING_PRIVATE}
    ${TESTING_PUBLIC}
)

add_executable(${NAME}Develop
    ${TESTING_COLLECTIVE}
)
set_property(TARGET ${NAME}Develop PROPERTY FOLDER "${NAME}")

target_include_directories(${NAME}Develop
    PUBLIC ${CMAKE_BINARY_DIR}/exports
)

if(NOT BUILD_MODULAR_LIBS)
target_link_libraries(${NAME}Develop
    ${NAME}
)
endif(NOT BUILD_MODULAR_LIBS)

我的代码中没有任何特定内容,因此出于这个问题的目的,我简化了一个测试用例。

library.h:

#pragma once

namespace Library
{

class Library
{
public:

    void testing();

};

} // namespace Library

Library.cpp:

#include <iostream>

#include "Library.h"

namespace Library
{

void Library::testing()
{
    std::cout << "Library API: Hello, world!.... VERSIONED!" << std::endl;
}

} // namespace Library

Test / Main.cpp:

#include <iostream>
#include <conio.h>

// Tried different error handling, I think I need preprocessors here for this... google didn't help.
// I feel that I should be referencing the DLL, not the header
// and I couldn't find information in wikis or CMake documentation.
#include "Library.h"

int main(int argc, char const *argv[])
{
    // The same applies for these two lines.
    Library::Library test;
    test.testing();

    std::cout << "Press any key to exit..." << std::endl;
    _getch();

    return 0;

}

我尝试过的内容:

  • 在引用该库的代码周围放置try / catch块。编辑:是的,我知道这很糟糕,可能永远无法正常工作,但是我不知道内部是否在调用库加载。
  • 使用和不使用选项库来编译程序的版本。 (老实说...这很糟糕...非常糟糕...预处理器指令可以解决这个问题,但这意味着每个人都想要一个量身定制的版本,而无需某些库就必须自行构建,而不是仅仅删除自己的dll。 d喜欢在那里,这就是我想做的。)
  • 手动'__declspec'声明可手动执行此操作,此方法有效,但我希望避免(如果可能)。那里有足够的信息,我能够将它们拼凑在一起,并且愿意这样做,但实际上,想法是像使用可执行文件或库那样,用类(用c ++术语)称为普通英语编写带有类的代码。 。

最后一点确实是我要完成的工作。我希望能够编写c ++代码,并使它对其他开发人员可读,而无需管理某些更复杂的功能,包括特定于平台的共享库加载。

0 个答案:

没有答案