跳转到内容
新建笔记

Qt 第三方库:头文件、静态目标、DLL 与导入库

头文件、链接库和运行库各负责一段

跳转到“头文件、链接库和运行库各负责一段”

使用 QCustomPlot 的预编译库时,通常仍需包含 qcustomplot.h:编译器要知道类型、成员和调用接口。库文件不能替代这些声明;某些模板和内联实现本来就位于头文件中。

文件或目标主要阶段内容与用途
头文件编译声明、类定义及可能的内联/模板实现
静态实现库链接目标代码按链接规则进入最终产物,仍可能依赖动态 Qt 等库
Windows 导入库链接描述动态库导出入口,帮助生成动态导入关系
DLL运行提供被导入的实现,并继续加载它自己的依赖

MSVC 的 .lib 既可能是静态实现库,也可能是 DLL 的导入库;MinGW 常见静态 .a 与导入 .dll.a。不能只凭后缀判断内容,更不能因为二者都参与链接就说导入库包含了全部实现。

头文件、库和 Qt Kit 应来自兼容的版本、编译器、架构和构建配置。已经链接 QCustomPlot 动态实现时,不应又把同一份 qcustomplot.cpp 编入应用;选择直接编译源码、建立静态目标或消费动态库中的一种路线。

先用源码目标复现原正弦图

跳转到“先用源码目标复现原正弦图”

以下使用 QCustomPlot 2.1.1 的 qcustomplot.h/.cpp。把原包中的两文件放到 thirdparty/qcustomplot/;不修改其实现。QCustomPlot 有自己的许可条件,实际项目应核对该版本的许可选项。

原稿两套 Test 类代码依赖未提供的 .ui 文件,现用代码布局保留全部绘图意图:1001 点、x 从 −5 到 5、sin(x)、蓝色折线、尺寸 3 的空心圆点、坐标范围、网格和 replot()。

main.cpp:

#include "qcustomplot.h"
#include <QApplication>
#include <QImage>
#include <QVBoxLayout>
#include <QVector>
#include <QWidget>
#include <cassert>
#include <cmath>
#include <iostream>
class Test final : public QWidget {
public:
explicit Test(QWidget *parent = nullptr) : QWidget(parent) {
auto *customPlot = new QCustomPlot(this);
auto *layout = new QVBoxLayout(this);
layout->addWidget(customPlot);
QCPGraph *graph = customPlot->addGraph();
QVector<double> x(1001), y(1001);
for (int i = 0; i < 1001; ++i) {
x[i] = i / 100.0 - 5.0;
y[i] = std::sin(x[i]);
}
graph->setData(x, y);
graph->setPen(QPen(Qt::blue));
graph->setLineStyle(QCPGraph::lsLine);
graph->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, 3));
customPlot->xAxis->setLabel(QStringLiteral("x"));
customPlot->yAxis->setLabel(QStringLiteral("sin(x)"));
customPlot->xAxis->setRange(-5, 5);
customPlot->yAxis->setRange(-1.5, 1.5);
customPlot->xAxis->grid()->setVisible(true);
customPlot->yAxis->grid()->setVisible(true);
customPlot->replot();
assert(graph->dataCount() == 1001);
assert(graph->data()->at(0)->key == -5.0);
assert(graph->data()->at(1000)->key == 5.0);
assert(std::abs(graph->data()->at(500)->value) < 1e-12);
assert(graph->pen().color() == QColor(Qt::blue));
assert(graph->scatterStyle().shape() == QCPScatterStyle::ssCircle);
assert(graph->scatterStyle().size() == 3);
assert(customPlot->xAxis->range().lower == -5);
assert(customPlot->yAxis->range().upper == 1.5);
assert(customPlot->xAxis->grid()->visible());
assert(customPlot->yAxis->grid()->visible());
}
};
int main(int argc, char **argv) {
QApplication app(argc, argv);
Test widget;
widget.resize(640, 400);
if (app.arguments().contains(QStringLiteral("--interactive"))) {
widget.show();
return app.exec();
}
QImage frame(widget.size(), QImage::Format_ARGB32);
frame.fill(Qt::transparent);
widget.render(&frame);
assert(!frame.isNull());
std::cout << "QCustomPlot " << QCUSTOMPLOT_VERSION_STR
<< ": 1001-point sine plot passed\n";
}

CMakeLists.txt 可以分别构建静态和动态 QCustomPlot:

cmake_minimum_required(VERSION 3.20)
project(QcpIntegration LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt6 REQUIRED COMPONENTS Widgets PrintSupport)
option(QCP_SHARED "Build QCustomPlot as a shared library" OFF)
if(QCP_SHARED)
add_library(qcustomplot SHARED
thirdparty/qcustomplot/qcustomplot.cpp
thirdparty/qcustomplot/qcustomplot.h)
target_compile_definitions(qcustomplot
PRIVATE QCUSTOMPLOT_COMPILE_LIBRARY
INTERFACE QCUSTOMPLOT_USE_LIBRARY)
else()
add_library(qcustomplot STATIC
thirdparty/qcustomplot/qcustomplot.cpp
thirdparty/qcustomplot/qcustomplot.h)
endif()
set_target_properties(qcustomplot PROPERTIES AUTOMOC ON)
target_include_directories(qcustomplot SYSTEM PUBLIC thirdparty/qcustomplot)
target_link_libraries(qcustomplot PUBLIC Qt6::Widgets Qt6::PrintSupport)
if(MINGW)
target_compile_options(qcustomplot PRIVATE -Wa,-mbig-obj)
endif()
add_executable(qcp_demo main.cpp)
target_link_libraries(qcp_demo PRIVATE qcustomplot)

QCustomPlot 内部的 QObject 类需要 moc,所以对库目标启用 AUTOMOC;示例 Test 自己没有增加元对象功能,不需要 Q_OBJECT。PrintSupport 是这个源码版本的依赖。MinGW 的大对象选项用于这份较大的合并源码,不能不分编译器地把该选项传给 MSVC。

默认分支是静态 QCustomPlot,QCP_SHARED=ON 是动态版本;使用不同构建目录验证两者。这里“静态 QCustomPlot”不表示整个程序已静态链接 Qt。动态构建中的 QCUSTOMPLOT_COMPILE_LIBRARY 只用于生成库,QCUSTOMPLOT_USE_LIBRARY 传给消费端;这与 2.1.1 头文件的导出/导入条件一致。

如果供应方已经提供匹配的 DLL、导入库和头文件,应用不再编译 qcustomplot.cpp。下面为 Windows 动态库消费项目的完整 CMake 文件,仍使用上面的 main.cpp。配置时通过 QCP_INCLUDE_DIR、QCP_IMPORT_LIBRARY 和 QCP_DLL 提供真实文件路径;用对应 Debug/Release 库,不把占位路径当成已安装依赖。

cmake_minimum_required(VERSION 3.20)
project(QcpBinaryConsumer LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt6 REQUIRED COMPONENTS Widgets PrintSupport)
set(QCP_INCLUDE_DIR "" CACHE PATH "Directory containing qcustomplot.h")
set(QCP_IMPORT_LIBRARY "" CACHE FILEPATH "Matching Windows import library")
set(QCP_DLL "" CACHE FILEPATH "Matching QCustomPlot DLL")
if(NOT EXISTS "${QCP_INCLUDE_DIR}/qcustomplot.h"
OR NOT EXISTS "${QCP_IMPORT_LIBRARY}" OR NOT EXISTS "${QCP_DLL}")
message(FATAL_ERROR "Supply matching QCustomPlot headers, import library and DLL")
endif()
add_library(qcp_binary SHARED IMPORTED)
set_target_properties(qcp_binary PROPERTIES
IMPORTED_IMPLIB "${QCP_IMPORT_LIBRARY}"
IMPORTED_LOCATION "${QCP_DLL}"
INTERFACE_INCLUDE_DIRECTORIES "${QCP_INCLUDE_DIR}"
INTERFACE_COMPILE_DEFINITIONS QCUSTOMPLOT_USE_LIBRARY
INTERFACE_LINK_LIBRARIES "Qt6::Widgets;Qt6::PrintSupport")
add_executable(qcp_demo main.cpp)
target_link_libraries(qcp_demo PRIVATE qcp_binary)
add_custom_command(TARGET qcp_demo POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"$<TARGET_FILE:qcp_binary>" "$<TARGET_FILE_DIR:qcp_demo>"
VERBATIM)

这只复制 QCustomPlot DLL,Qt 和编译器运行库仍按Windows 发布处理。qmake 项目中的 INCLUDEPATH 与 LIBS += -L... -l... 也分别解决头文件和链接库;动态消费端同样要设置相应导入宏。运行时找不到 DLL 与链接时找不到导入库是不同故障。

原第三方清单如何补齐

跳转到“原第三方清单如何补齐”

原短笔记还列出了 qrcode 和 QHotkey:

项目线索可以保留的用途接入前仍需确认
qrcode生成二维码名称不足以唯一确定库;补项目地址、版本、编码接口及许可后再决定构建方式
Skycoder42/QHotkey应用不在前台时仍接收全局热键原笔记未给地址,此处提供同名上游供核对;查平台后端、注册失败结果、系统占用及 Qt 版本

QHotkey 上游说明支持 Windows、macOS 和 X11,并说明它的现有实现不支持 Wayland;不要把普通窗口内快捷键与跨应用全局热键混为一谈,也不据此断言所有 Wayland 热键方案都不可能。本页没有执行全局热键注册或确定原 qrcode 所指项目。

本页实际验证聚焦 QCustomPlot 源码静态目标、源码动态目标及分离的预编译库消费流程;绘图程序默认进行数据/样式断言和一次绘制后结束,--interactive 可显示窗口。进一步的轴刻度设置见QCustomPlot 坐标轴刻度。

来源:头文件与库原记录、第三方组件原清单、QCustomPlot 官方网站。