C++ 项目:使用 GSL 数学运算库 & C++ 调用Python

Part.I Introduction

本文是一个项目的使用教程,此项目是一个使用 GSL 的小项目,还有 C++ 调用 Python。项目虽简单,但麻雀虽小五脏俱全,笔者觉得此项目架构还是比较明晰的,值得一看。

在这里插入图片描述

项目所包含文件如下:

.
 ─app_test
│  ├─TEMP_TestGSL
│  └─TEMP_TestPython
├─LibGSL
│  ├─example
│  └─gexport
├─LibPython
│  ├─example
│  │  └─__pycache__
│  └─gexport
└─_doc

请戳我下载,下面展示部分文件


Chap.I CMakeLists

下面是一个主 CMakeLists。

# 要求的 CMAKE 最低版本号
cmake_minimum_required(VERSION 3.0.0)
# 项目名和版本号  
project(Temp VERSION 1.0.0)
# information message

# 编译器设置
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)

# 编译选项设置
if(CMAKE_SYSTEM_NAME MATCHES "Windows")
    SET(BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}_Windows)
    add_compile_options(/bigobj)
    add_compile_options(/MP)
    add_compile_options(/w)
endif()

if(COMPILER_SUPPORTS_CXX11)
    set(CMAKE_CXX_STANDARD 11)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread")
elseif(COMPILER_SUPPORTS_CXX0X)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -pthread")
else()
    message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()

# Choose different compilation configurations according to VS compilation
# 根据VS编译选择不同的编译配置
if(CMAKE_BUILD_TYPE MATCHES "Release")
    set(CMAKE_BUILD_POSTFIX "${CMAKE_RELEASE_POSTFIX}")
elseif(CMAKE_BUILD_TYPE MATCHES "Debug")
    set(CMAKE_BUILD_POSTFIX "${CMAKE_DEBUG_POSTFIX}")
elseif(CMAKE_BUILD_TYPE MATCHES "RelWithDebInfo")
    set(CMAKE_BUILD_POSTFIX "${CMAKE_RELWITHDEBINFO_POSTFIX}")
elseif(CMAKE_BUILD_TYPE MATCHES "MinSizeRel")
    set(CMAKE_BUILD_POSTFIX "${CMAKE_MINSIZEREL_POSTFIX}")
else()
    set(CMAKE_BUILD_POSTFIX "")
endif()

# Set the ROOT and subdirectory, you should put the CMakeList.txt in these file directories
# 设置根目录和子目录时,应将CMakeList.txt文件在这些文件目录中
set(ROOT ${PROJECT_SOURCE_DIR})
set(EXECUTABLE_OUTPUT_PATH ${BUILD_DIR}/Bin)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BUILD_DIR}/Bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${BUILD_DIR}/Lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${BUILD_DIR}/Lib)

set(CMAKE_DEBUG_POSTFIX "d")
set(CMAKE_RELEASE_POSTFIX "")
set(CMAKE_RELWITHDEBINFO_POSTFIX "rd")
set(CMAKE_MINSIZEREL_POSTFIX "s")


# 为调试Cmake输出消息
message(STATUS "operation system is : ${CMAKE_SYSTEM}")
message(STATUS "current platform is : ${CMAKE_SYSTEM_NAME}")
message(STATUS "CMake version    is : ${CMAKE_SYSTEM_VERSION}")
message(STATUS "C compiler       is : ${CMAKE_C_COMPILER}")
message(STATUS "C++ compiler     is : ${CMAKE_CXX_COMPILER}")
message(STATUS "Build directory  is : ${BUILD_DIR}")
message(STATUS "The program main directory is : ${ROOT}")



# 设置一些文件夹,库里面的 CMake 会用到
set(file_fold 
    example gexport
    )
set(PrintFile FALSE)


# ==================================================================================
# 为了测试 Python,各位不用开即可
option(Main_USE_PYTHON    "using "  OFF)

# 链接三方库
if(CMAKE_SYSTEM_NAME MATCHES "Windows")
    #For windows
    # ==============================================================================
    if (NOT DEFINED Third_GSL_ROOT)
        find_path(Third_GSL_ROOT         HINTS "${Third_GSL_ROOT}"          "$ENV{Third_GSL_ROOT}            ")
    endif()
    # ==============================================================================
endif()


set(LibGSL              LibGSL)
set(LibGSLSrc           ${ROOT}/${LibGSL})
add_subdirectory(${LibGSLSrc}       ${BUILD_DIR}/${LibGSL})
SET_PROPERTY(TARGET ${LibGSL}       PROPERTY FOLDER "LIB")


if(Main_USE_PYTHON)
    set(LibPython             LibPython)
    set(LibPythonSrc          ${ROOT}/${LibPython})
    add_subdirectory(${LibPythonSrc}      ${BUILD_DIR}/${LibPython})
    SET_PROPERTY(TARGET ${LibPython}      PROPERTY FOLDER "LIB")
endif()

# 使用文件夹选项打开
SET_PROPERTY(GLOBAL PROPERTY USE_FOLDERS ON) 

Chap.II ExportLibGSL.h

#ifndef EXPORT_LibGSL_H
#define EXPORT_LibGSL_H

#if defined(_MSC_VER)
#pragma warning(disable : 4244)
#pragma warning(disable : 4251)
#pragma warning(disable : 4275)
#pragma warning(disable : 4512)
#pragma warning(disable : 4267)
#pragma warning(disable : 4702)
#pragma warning(disable : 4511)
#pragma warning(disable : 4996)
#endif

#if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BCPLUSPLUS__) || defined(__MWERKS__)
#if defined(TEMP_LibGSL_LIBRARY)
#define LibGSL_LIBRARY_EXPORT __declspec(dllexport)
#else
#define LibGSL_LIBRARY_EXPORT __declspec(dllimport)
#endif
#else
#define LibGSL_LIBRARY_EXPORT
#endif

#ifdef _MSC_VER
#if (_MSC_VER >= 1300)
#define __STL_MEMBER_TEMPLATES
#endif
#endif

#include <string>
#include <vector>
using namespace std;

#ifndef SIZE_INT
#define SIZE_INT sizeof(int)
#endif

#ifndef SIZE_DBL
#define SIZE_DBL sizeof(double)
#endif // !SIZE_DBL
#endif

Chap.III test_python.cpp

C++ 调用 Python 的主要代码

#include <iostream>
#include "test_python.h"

using namespace std;

namespace temp
{
    t_test_python::t_test_python() { }

    t_test_python::~t_test_python()
    {

    }

    int t_test_python::_pythonInit() {
        Py_Initialize();
        int ret = Py_IsInitialized();
        if (ret == 0) {
            cout << "Py_Initialize error" << endl;
            return kError;
        }
        return kSuccess;
    }


    void t_test_python::_pythonCleanup() {
        Py_Finalize();
    }


    int t_test_python::_callPythonAdd(PyObject* module, int a, int b) {
        //获取模块字典属性
        PyObject* pDict = PyModule_GetDict(module);
        if (pDict == nullptr) {
            PyErr_Print();
            std::cout << "PyModule_GetDict error" << std::endl;
            return kError;
        }

        //直接获取模块中的函数
        PyObject* addFunc = PyDict_GetItemString(pDict, "add");
        if (addFunc == nullptr) {
            std::cout << "PyDict_GetItemString 'add' not found" << std::endl;
            return kError;
        }

        // 构造python 函数入参, 接收2
        // see: https://docs.python.org/zh-cn/3.7/c-api/arg.html?highlight=pyarg_parse#c.PyArg_Parse
        PyObject* pArg = Py_BuildValue("(i,i)", a, b);

        //调用函数,并得到 python 类型的返回值
        PyObject* result = PyEval_CallObject(addFunc, pArg);

        int ret = 0;
        //将python类型的返回值转换为c/c++类型
        PyArg_Parse(result, "i", &ret);
        return ret;
    }


    PyObject* t_test_python::_pythonImportModule(const char* pyDir, const char* name) {
        // 引入当前路径,否则下面模块不能正常导入
        char tempPath[256] = {};
        sprintf(tempPath, "sys.path.append('%s')", pyDir);
        PyRun_SimpleString("import sys");
        //PyRun_SimpleString("sys.path.append('./')");
        PyRun_SimpleString(tempPath);
        PyRun_SimpleString("print('----------------------------------------')");
        PyRun_SimpleString("print('curr sys.path: ', sys.path)");
        PyRun_SimpleString("print('----------------------------------------')");
        // import ${name}
        PyObject* module = PyImport_ImportModule(name);
        if (module == nullptr) {
            PyErr_Print();
            cout << "PyImport_ImportModule '" << name << "' not found" << endl;
            return nullptr;
        }

        return module;
    }


    int t_test_python::_callPythonGetName(PyObject* module, std::string firstName, std::string& outName) {
        //获取模块字典属性
        PyObject* pDict = PyModule_GetDict(module);
        if (pDict == nullptr) {
            PyErr_Print();
            std::cout << "PyModule_GetDict error" << std::endl;
            return kError;
        }

        //直接获取模块中的函数
        PyObject* addFunc = PyDict_GetItemString(pDict, "get_name");
        if (addFunc == nullptr) {
            std::cout << "PyDict_GetItemString 'add' not found" << std::endl;
            return kError;
        }

        // 构造python 函数入参, 接收2
        // see: https://docs.python.org/zh-cn/3.7/c-api/arg.html?highlight=pyarg_parse#c.PyArg_Parse
        PyObject* pArg = Py_BuildValue("(s)", firstName.c_str());

        //调用函数,并得到python类型的返回值
        PyObject* result = PyEval_CallObject(addFunc, pArg);

        char* name = nullptr;
        //将python类型的返回值转换为c/c++类型
        PyArg_Parse(result, "s", &name);

        char tempStr[256] = {};
        int strLen = strlen(name);
        if (strLen > 256) {
            return kError;
        }
        strcpy(tempStr, name);
        outName = tempStr;
        return kSuccess;
    }


    int t_test_python::processBatch()
    {
        _pythonInit();

        //直接运行 python 代码
        PyRun_SimpleString("print('---------- Hello Python form C/C++ ----------')");
        PyRun_SimpleString("print('Test BEGIN ...')");
        //调用 Python 脚本
        PyObject* helloModule = _pythonImportModule("A:/aWork/scripts/AURORA/V1/LibPython/example", "hello");    // 这里最好还是给绝对路径吧
        if (helloModule == nullptr) {
            return -1;
        }

        // call python add function
        int result = _callPythonAdd(helloModule, 1, 3);
        cout << "1 + 3 = " << result << endl;

        // call python get_name function
        std::string fullName;
        _callPythonGetName(helloModule, "Summer", fullName);
        cout << fullName << endl;
        PyRun_SimpleString("print('Test END!')");
        _pythonCleanup();
    }
}

Part.II GSL 使用方法

首先需要安装 CMake、VS Studio

为了防止不必要的歧义,下面将项目的根目录称为『当前目录』

首先将_doc文件夹下的gsl.zip解压,放到一个你不常动的目录中,将这个目录(或 这个目录/gsl)称为『gsl目录』,懂我意思吧

1、在当前目录下新建 build 文件夹

2、打开 CMake,源码路径设置为当前目录,build 路径设置为 当前目录/build

3、点击 Configure,之后配置根据自己实际情况配,配好点击 Finish

在这里插入图片描述

4、会报错,不要急,把 gsl 目录赋给 Third_GSL_ROOT,再次点击Configure

在这里插入图片描述

5、依次点击GenerateOpen Project,打开项目

6、将 TEMP_TestGSL 设为启动项目

在这里插入图片描述

7、快捷键 F5 运行,得到结果

在这里插入图片描述

完事!

Part.III C++ 调用 Python 使用方法

1、上面第三步勾选 Main_USE_PYTHON,把 Python 的路径给它

2、依次点击ConfigureGenerateOpen Project,打开项目

3、将 TEMP_TestPython 设为启动项目

在这里插入图片描述

4、快捷键 F5 运行,得到结果
在这里插入图片描述

完事!

相关博客

  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流浪猪头拯救地球

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值