【静态库、动态库】C++生成、使用静态,动态库文件

本文主要介绍在Linux环境下C++如何生成库文件,如何使用库文件,将以几个例子进行说明库开发人员角度和应用开发人员(使用库文件人员)角度进行说明。

  1. C++静态库
  2. C++多个文件的静态库
  3. C++动态库

1.静态库

编译时静态库必须存在
静态库会增加编译后的可执行文件大小

1.1.使用单个文件组成库

1.1.1.目录结构

staticlibtest1r
├── libs
│   ├── headers
│   │   └── increment.hpp
│   ├── increment.cpp
└── src
    ├── headers
    ├── libs
    └── test_increment.cpp

1.1.2.编译并使用库

  1. 编译生成库文件
cd libs
# statictest1/libs目录下
# -c 代表只编译不链接
g++ -c increment.cpp -o increment.o
# 生成静态库文件
ar rcs libincrement.a increment.o

会在statictest1/libs下生成increment.olibincrement.a,后者就是我们要的库文件
2. 拷贝库文件和头文件
将其拷贝到statictest1/src/libs下

cd ..
# statictest1目录下
# 拷贝
cp libs/libincrement.a src/libs/
cp libs/headers/increment.hpp src/headers/
  1. 编译运行测试
cd src
# statictest1/src目录下
# 编译可执行文件 
g++ test_increment.cpp -L./libs -lincrement -o test_increment
# 执行
./test_increment
# 运行结果
Before incrementing: a b c d e 
After incrementing: b c d e f 

1.1.3.文件内容

increment.hpp文件内容

#ifndef INCREMENT_H
#define INCREMENT_H

#include <vector>

class CharIncrement {
public:
    static void incrementChars(std::vector<char>& chars);
};

#endif // INCREMENT_H

increment.cpp文件内容

#include "./headers/increment.hpp"

void CharIncrement::incrementChars(std::vector<char>& chars) {
    for (auto& c : chars) {
        c = c + 1;
    }
}

test_increment.cpp文件内容

#include <iostream>
#include <vector>
#include "./headers/increment.hpp"

int main() {
    std::vector<char> chars = {'a', 'b', 'c', 'd', 'e'};
    
    std::cout << "Before incrementing: ";
    for (const auto& c : chars) {
        std::cout << c << " ";
    }
    std::cout << std::endl;

    CharIncrement::incrementChars(chars);

    std::cout << "After incrementing: ";
    for (const auto& c : chars) {
        std::cout << c << " ";
    }
    std::cout << std::endl;

    return 0;
}

1.2.使用多个文件组成的库

1.2.1.目录结构

staticlibtest2
├── cppsrc
│   ├── pics
│   │   └── input_image.jpg
│   └── src
│       ├── headers
│       ├── libs
│       └── test_image.cpp
└── libsrc
    ├── headers
    │   ├── image_loader.hpp
    │   ├── image_processor.hpp
    │   └── image_saver.hpp
    ├── libs
    ├── image_loader.cpp
    ├── image_processor.cpp
    └── image_saver.cpp

1.2.2.编译并使用库

  1. 编译生成库文件
cd libsrc
# statictest2/libsrc目录下
g++ -c image_loader.cpp -o image_loader.o `pkg-config --cflags opencv4`
g++ -c image_processor.cpp -o image_processor.o `pkg-config --cflags opencv4`
g++ -c image_saver.cpp -o image_saver.o `pkg-config --cflags opencv4`
# 生成静态库文件
ar rcs ./libs/libimage_processing.a image_loader.o image_processor.o image_saver.o

# 上述四行也可以简化成以下一行
# ar rcs ./libs/libimage_processing.a image_loader.cpp image_processor.cpp image_saver.cpp `pkg-config --cflags opencv4`

会在statictest2/libsrc下生成image_loader.oimage_processor.oimage_saver.o三个目标文件,并在statictest2/libsrc/libs下生成一个库文件libimage_processing.a
2. 拷贝库文件和头文件

cd ..
# statictest2目录下
cp libsrc/libs/libimage_processing.a cppsrc/src/libs/
cp libsrc/headers/* cppsrc/src/headers/
  1. 编译运行测试
cd cppsrc/src
# statictest2/cppsrc/src目录下
# 编译可执行文件 
g++ test_image.cpp  -L./libs -limage_processing `pkg-config --cflags --libs opencv4` -o test_image
# 执行
./test_image
# 运行结果
Image loaded successfully. Converting to grayscale...
Grayscale image saved successfully.
Applying Gaussian blur...
Blurred image saved successfully.

运行后的图片
多个文件组成的静态库输出图

1.2.3.文件内容

image_loader.cpp文件内容

#include "./headers/image_loader.hpp"
#include <fstream>
#include <stdexcept>


ImageLoader::ImageLoader(const std::string& filename){
    Image = load(filename);
    Filename = filename;
}
ImageLoader::ImageLoader(const std::string& filename,const int width,const int height){
    Image = load(filename);
    Filename = filename;
    Width = width;
    Height = height;
}
cv::Mat ImageLoader::load(const std::string& filename) {
    cv::Mat image = cv::imread(filename, cv::IMREAD_COLOR);
    if (image.empty()) {
        throw std::runtime_error("Failed to load image");
    }
    return image;
}

image_loader.hpp文件内容

#ifndef IMAGE_LOADER_H
#define IMAGE_LOADER_H

#include <string>
#include <vector>
#include <opencv2/opencv.hpp>

class ImageLoader {
public:
    ImageLoader() {

    }
    ImageLoader(const std::string& filename);
    ImageLoader(const std::string& filename,const int width,const int height);
    cv::Mat load(const std::string& filename);
    cv::Mat Image;
    std::string Filename;
    int Width;
    int Height;
};

#endif // IMAGE_LOADER_H

image_processor.cpp文件内容

#include "./headers/image_processor.hpp"
#include <opencv2/opencv.hpp>

void ImageProcessor::convertToGrayscale(cv::Mat& image) {
    cv::cvtColor(image, image, cv::COLOR_BGR2GRAY);
}

void ImageProcessor::applyGaussianBlur(cv::Mat& image, int kernelSize, double sigma) {
    cv::GaussianBlur(image, image, cv::Size(kernelSize, kernelSize), sigma);
}

image_processor.hpp文件内容

#ifndef IMAGE_PROCESSOR_H
#define IMAGE_PROCESSOR_H

#include <opencv2/opencv.hpp>

class ImageProcessor {
public:
    static void convertToGrayscale(cv::Mat& image);
    static void applyGaussianBlur(cv::Mat& image, int kernelSize, double sigma);
};

#endif // IMAGE_PROCESSOR_H

image_saver.cpp文件内容

#include "./headers/image_saver.hpp"
#include <opencv2/opencv.hpp>

void ImageSaver::save(const cv::Mat& image, const std::string& filename) {
    if (!cv::imwrite(filename, image)) {
        throw std::runtime_error("Failed to save image");
    }
}

image_saver.hpp文件内容

#ifndef IMAGE_SAVER_H
#define IMAGE_SAVER_H

#include <opencv2/opencv.hpp>

class ImageSaver {
public:
    static void save(const cv::Mat& image, const std::string& filename);
};

#endif // IMAGE_SAVER_H

test_image.cpp文件内容

#include <iostream>
#include <string>
#include "./headers/image_loader.hpp"
#include "./headers/image_processor.hpp"
#include "./headers/image_saver.hpp"

int main() {
    try {
        std::string inputFilename = "../pics/input_image.jpg";
        std::string outputFilename1 = "../pics/output_grayscale.jpg";
        std::string outputFilename2 = "../pics/output_blur.jpg";

        ImageLoader il = ImageLoader(inputFilename);
        cv::Mat image = il.load(inputFilename);
        cv::Mat image2 = image.clone();

        std::cout << "Image loaded successfully. Converting to grayscale..." << std::endl;
        ImageProcessor::convertToGrayscale(image);
        ImageSaver::save(image, outputFilename1);
        std::cout << "Grayscale image saved successfully." << std::endl;

        std::cout << "Applying Gaussian blur..." << std::endl;
        ImageProcessor::applyGaussianBlur(image2, 11, 5.0);
        ImageSaver::save(image2, outputFilename2);
        std::cout << "Blurred image saved successfully." << std::endl;
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }

    return 0;
}

2.动态库

运行时动态库必须存在
动态库使用动态链接,相比静态库可让可执行文件变小

2.1.目录结构

alibtest2
├── app
│   ├── pics
│   │   └── input_image.jpg
│   └── src
│       ├── headers
│       ├── libs
│       └── test_image.cpp
└── lib
    ├── libs
    └── src
	    ├── headers
	    │   ├── image_loader.hpp
	    │   ├── image_processor.hpp
	    │   └── image_saver.hpp
        ├── image_loader.cpp
        ├── image_processor.cpp
        └── image_saver.cpp

2.2.编译并使用库

  1. 编译生成库
cd lib/src
# alibtest2/lib/src下
g++ -fPIC -c image_loader.cpp -o image_loader.o `pkg-config --cflags opencv4`
g++ -fPIC -c image_processor.cpp -o image_processor.o `pkg-config --cflags opencv4`
g++ -fPIC -c image_saver.cpp -o image_saver.o `pkg-config --cflags opencv4`
# 编译
g++  -shared -fPIC -o ../libs/libimage_processing.so image_loader.o image_processor.o image_saver.o
# -fPIC:
# 生成位置无关代码(Position Independent Code)。这对于创建共享库很重要,因为它允许库代码在内存中的任何位置加载和执行。
  1. 拷贝头文件和动态库
cp headers/* ../../app/src/headers
cp ../libs/libimage_processing.so ../../app/src/libs/
  1. 更新动态库加载路径
    将库文件路径添加进动态库搜索路径,即在/etc/ld.so.conf.d/目录下添加me.conf文件,
    me.conf内容:/home/gh/workspace/libtest/alibtest1_app/src/libs
    添加成功后使用ldconfig重新加载
echo "/home/gh/workspace/libtest/alibtest2/lib/libs" >> /etc/ld.so.conf.d/me.conf
ldconfig

若少了这一步,强制编译出的运行文件还无法动态连接到库
无法正确加载动态连接库图

  1. 编译运行测试
cd ../../app/src
# alibtest2/app/src下
# 编译
g++ test_image.cpp -L./libs -limage_processing `pkg-config --cflags --libs opencv4` -o test_image
# 查看库文件映射情况
# ldd test_image
# 运行
./test_image
# 运行结果
root@gh:/home/gh/workspace/libtest/alibtest2/app/src# ./test_image 
Image loaded successfully. Resizing width...
Resize width image saved successfully.
Resizing height...
Resize height image saved successfully.

在app/src/pics目录下生成两个输出图像output_resizewidth.jpgoutput_resizeheight.jpg
5. 运行结果
原图与输出图像
动态库输出图

2.3.文件内容

test_image.cpp文件内容

#include <iostream>
#include <string>
#include "./headers/image_loader.hpp"
#include "./headers/image_processor.hpp"
#include "./headers/image_saver.hpp"

int main() {
    try {
        std::string inputFilename = "../pics/input_image.jpg";
        std::string outputFilename1 = "../pics/output_resizewidth.jpg";
        std::string outputFilename2 = "../pics/output_resizeheight.jpg";

        ImageProcessor imagep;

        ImageLoader il = ImageLoader(inputFilename);
        cv::Mat image = il.load(inputFilename);
        cv::Mat image2 = image.clone();

        std::cout << "Image loaded successfully. Resizing width..." << std::endl;
        imagep.resizeWidth(image);
        ImageSaver::save(image, outputFilename1);
        std::cout << "Resize width image saved successfully." << std::endl;

        std::cout << "Resizing height..." << std::endl;
        imagep.resizeHeight(image2);
        ImageSaver::save(image2, outputFilename2);
        std::cout << "Resize height image saved successfully." << std::endl;
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }

    return 0;
}

image_loader.cpp文件内容

#include "./headers/image_loader.hpp"
#include <fstream>
#include <stdexcept>


ImageLoader::ImageLoader(const std::string& filename){
    Image = load(filename);
    Filename = filename;
}
ImageLoader::ImageLoader(const std::string& filename,const int width,const int height){
    Image = load(filename);
    Filename = filename;
    Width = width;
    Height = height;
}
cv::Mat ImageLoader::load(const std::string& filename) {
    cv::Mat image = cv::imread(filename, cv::IMREAD_COLOR);
    if (image.empty()) {
        throw std::runtime_error("Failed to load image");
    }
    return image;
}

image_loader.hpp文件内容

#ifndef IMAGE_LOADER_H
#define IMAGE_LOADER_H

#include <string>
#include <vector>
#include <opencv2/opencv.hpp>

class ImageLoader {
public:
    ImageLoader() {

    }
    ImageLoader(const std::string& filename);
    ImageLoader(const std::string& filename,const int width,const int height);
    cv::Mat load(const std::string& filename);
    cv::Mat Image;
    std::string Filename;
    int Width;
    int Height;
};

#endif // IMAGE_LOADER_H

image_processor.cpp文件内容

#include "./headers/image_processor.hpp"
#include <opencv2/imgproc.hpp>

void ImageProcessor::resizeWidth(cv::Mat& image) {
    int newWidth = image.cols / 2;
    cv::resize(image, image, cv::Size(newWidth, image.rows));
}

void ImageProcessor::resizeHeight(cv::Mat& image) {
    int newHeight = image.rows / 2;
    cv::resize(image, image, cv::Size(image.cols, newHeight));
}

image_processor.hpp文件内容

#ifndef IMAGE_PROCESSOR_H
#define IMAGE_PROCESSOR_H

#include <opencv2/opencv.hpp>

class ImageProcessor {
public:
    void resizeWidth(cv::Mat& image);
    void resizeHeight(cv::Mat& image);
};

#endif // IMAGE_PROCESSOR_H

image_saver.cpp文件内容

#include "./headers/image_saver.hpp"
#include <opencv2/opencv.hpp>

void ImageSaver::save(const cv::Mat& image, const std::string& filename) {
    if (!cv::imwrite(filename, image)) {
        throw std::runtime_error("Failed to save image");
    }
}

image_saver.hpp文件内容

#ifndef IMAGE_SAVER_H
#define IMAGE_SAVER_H

#include <opencv2/opencv.hpp>

class ImageSaver {
public:
    static void save(const cv::Mat& image, const std::string& filename);
};

#endif // IMAGE_SAVER_H
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值