将python工程生成cmake包并使用find_package验证

144 篇文章 6 订阅
8 篇文章 20 订阅

这一段我们在借鉴ros的genmsg包的实现来创建我们的数据定义到.h文件的自动生成机制。但是genmsg是ros中基于python写的包,还依赖gencpp等包。鉴于此,我们分成几步来做这件事。

(1)将ros中的genmsg包及其依赖的包都抽出来,变成一个与ros环境无关的工程gendo,然后在该工程中进行msg文件到.h文件的测试。但是没有使用catkin_make和cmake,而是用的python脚本。

(2)在gendo中编写一个cpp和.h文件,里面定义一个函数。在该函数中创建一个python运行环境,调用genmsg的函数,并将所需要的参数传进去。将cpp和.h打包成cmake包(不仅仅是.so,而是包括了XXXConfig.cmake文件)。

(3)再创建一个cmake工程,里面有一个cpp,包含了一个main(),里面调用前面的得到的package中定义的函数,验证前面编译的包能否通过find_package()找到。

(4)修改前面生成包,并在里面添加一个宏。该宏接收用户输入的msg文件的名称、路径、依赖的msg的名称、路径,然后将这些参数以及其他参数传给gendo中的函数,并调用该函数,生成.h文件。

上述为我们进行改造的思路。其中第一步已经完成了。本文讲述第二步和第三步。第四步后面再探索。

这里,我们先不用gencpp和genmsg包。而是使用了两个更简单的python文件构成的包来验证上述(1)(2)(3)。

实践

两个工程(在Ubuntu下进行的):

(1)cpp_call_python完成cpp封装python工程,然后将cpp打包成cmake包,供其他cmake包使用find_package调用。

(2)my_test,使用find_package找到上述包,并测试使用里面封装的cpp函数(最终调用python脚本)。

1. cpp_call_python工程目录如下:

其中,Test001.py里面调用了Test002.py里面的函数。而a.cpp里面调用了Test001.py里面的函数。我们的目标是把a.cpp连同a.h封装成一个库。aTest.cpp是内部测试函数,验证能否使用a.cpp中的函数。

Test002.py

def Hello():
    print("Hello lijie")

Test001.py

import sys
import Test002

sys.path.append('/home/xuec07/code/test/cpp_call_python')

def aaa():
    Test002.Hello()

def add(a,b):
    return a + b

# def TestDict(dict):
#     print(dict)
#     dict["Age"] = 17
#     return dict

# class Persion:
#     def greet(self,greetStr):
#         print(greetStr)

a.h

#ifndef CDD18C7C_8F66_477A_A8C6_8CA086F626E9
#define CDD18C7C_8F66_477A_A8C6_8CA086F626E9

void HelloWorld();

#endif /* CDD18C7C_8F66_477A_A8C6_8CA086F626E9 */

a.cpp

#include <iostream>
#include <stdio.h>
#include <Python.h>
#include "a.h"

// using namespace std;

// void HelloWorld();
// // void Add();
// // void TestTranferDict();
// // void TestClass();

// int main() 
// {
//     std::cout << "Starting Test ..." << std::endl;
//     HelloWorld();  
//     // cout << "Add()--------------------" << endl;  
//     // Add();  
//     // cout << "TestDict-----------------" << endl;  
//     // TestTransferDict();  import sys
//     // cout << "TestClass----------------" << endl;  
//     // TestClass();  
  
//     // system("pause");  
//     return 0; 
// }

//调用输出"Hello World"函数  
void HelloWorld()  
{ 
    // Py_SetPythonHome(L"/usr/include/python3.8");
    // Py_SetPythonHome(L"/usr/lib/python3.8");
    
    Py_Initialize();              //使用python之前,要调用Py_Initialize();这个函数进行初始化  
    PyObject * pModule = NULL;    //声明变量  
    PyObject * pFunc = NULL;  
    PyRun_SimpleString("import sys");
    //PyRun_SimpleString("sys.path.append('./')");
     PyRun_SimpleString("sys.path.append('/home/xuec07/code/test/cpp_call_python')");
    // PyRun_SimpleString("sys.path.append('/home/xuec07/code/test/cpp_call_python/Test002.py')");
    pModule =PyImport_ImportModule("Test001");              //这里是要调用的Python文件名  
    std::cout << "pModule=" << pModule << std::endl;
    if (pModule)
    {
        pFunc= PyObject_GetAttrString(pModule, "aaa");   //这里是要调用的函数名
        std::cout << "pFunc" << pFunc << std::endl;
        PyEval_CallObject(pFunc, NULL); //调用函数,NULL表示参数为空
    }
    else
    {
        printf("Module fail");
    }
     
    Py_Finalize();                //调用Py_Finalize,这个和Py_Initialize相对应的.  
}  
  
// //调用Add函数,传两个int型参数  
// void Add()  
// {  
//     Py_Initialize();  
  
//     PyObject * pModule = NULL;      
//     PyObject * pFunc = NULL;        
//     pModule =PyImport_ImportModule("Test001");      //Test001:Python文件名  
//     pFunc= PyObject_GetAttrString(pModule, "add");  //Add:Python文件中的函数名  
//   //创建参数:  
//     PyObject *pArgs = PyTuple_New(2);               //函数调用的参数传递均是以元组的形式打包的,2表示参数个数  
//     PyTuple_SetItem(pArgs, 0, Py_BuildValue("i", 5));//0---序号  i表示创建int型变量  
//     PyTuple_SetItem(pArgs, 1, Py_BuildValue("i", 7));//1---序号  
//   //返回值  
//     PyObject *pReturn = NULL;  
//     pReturn = PyEval_CallObject(pFunc, pArgs);      //调用函数  
//   //将返回值转换为int类型  
//     int result;  
//     PyArg_Parse(pReturn, "i", &result);    //i表示转换成int型变量  
//     cout << "5+7 = " << result << endl;  
  
//     Py_Finalize();                  
// }  
  
// //参数传递的类型为字典  
// void TestTransferDict()  
// {  
//     Py_Initialize();  
  
//     PyObject * pModule = NULL;      
//     PyObject * pFunc = NULL;        
//     pModule =PyImport_ImportModule("Test001");      //Test001:Python文件名  
//     pFunc= PyObject_GetAttrString(pModule, "TestDict"); //Add:Python文件中的函数名  
//   //创建参数:  
//     PyObject *pArgs = PyTuple_New(1);   
//     PyObject *pDict = PyDict_New();   //创建字典类型变量  
//     PyDict_SetItemString(pDict, "Name", Py_BuildValue("s", "WangYao")); //往字典类型变量中填充数据  
//     PyDict_SetItemString(pDict, "Age", Py_BuildValue("i", 25));         //往字典类型变量中填充数据  
//     PyTuple_SetItem(pArgs, 0, pDict);//0---序号  将字典类型变量添加到参数元组中  
//   //返回值  
//     PyObject *pReturn = NULL;  
//     pReturn = PyEval_CallObject(pFunc, pArgs);      //调用函数  
//   //处理返回值:  
//     int size = PyDict_Size(pReturn);  
//     cout << "返回字典的大小为: " << size << endl;  
//     PyObject *pNewAge = PyDict_GetItemString(pReturn, "Age");  
//     int newAge;  
//     PyArg_Parse(pNewAge, "i", &newAge);  
//     cout << "True Age: " << newAge << endl;  
      
//     Py_Finalize();                  
// }  
  
// //测试类  
// void TestClass()  
// {  
//     Py_Initialize();  
  
//     PyObject * pModule = NULL;      
//     PyObject * pFunc = NULL;        
//     pModule =PyImport_ImportModule("Test001");      //Test001:Python文件名  
//     pFunc= PyObject_GetAttrString(pModule, "TestDict"); //Add:Python文件中的函数名  
//   //获取Person类  
//     PyObject *pClassPerson = PyObject_GetAttrString(pModule, "Person");  
//     //创建Person类的实例  
//     PyObject *pInstancePerson = PyInstance_New(pClassPerson, NULL, NULL);  
//     //调用方法  
//     PyObject_CallMethod(pInstancePerson, "greet", "s", "Hello Kitty");   //s表示传递的是字符串,值为"Hello Kitty"  
  
//     Py_Finalize(); 
// }           

CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
project(mytest)
add_library(test1 a.cpp a.h)
SET(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR}/install)
find_package(PythonLibs REQUIRED)
find_package(Python3 COMPONENTS Interpreter Development REQUIRED)
include_directories(/usr/include/python3.8)
target_include_directories(test1 PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>)
set_target_properties(test1 PROPERTIES PUBLIC_HEADER "a.h")
install(TARGETS test1
    EXPORT test1-targets
    PUBLIC_HEADER DESTINATION include
    ARCHIVE DESTINATION lib
    LIBRARY DESTINATION lib
    RUNTIME DESTINATION bin)
install(EXPORT test1-targets
    NAMESPACE mytest::
    FILE test1-config.cmake
    DESTINATION lib/cmake/test1)

执行编译后,生成libtest1.a在build目录下,而后因为执行install,会将include目录和lib目录移动到外面。而表征我们生成的是cmake包的test1-config.cmake文件则在CMakeFiles\Export\lib\cmake\test1下。

2. my_test工程目录如下:

 test.cpp

#include <iostream>
#include <stdio.h>
#include "a.h"

// void Add();
// void TestTranferDict();
// void TestClass();

int main() 
{
    std::cout << "Starting Test ..." << std::endl;
    HelloWorld();  
    // cout << "Add()--------------------" << endl;  
    // Add();  
    // cout << "TestDict-----------------" << endl;  
    // TestTransferDict();  import sys
    // cout << "TestClass----------------" << endl;  
    // TestClass();  
  
    // system("pause");  
    return 0; 
}

CMakeLists.txt

project(myapp)
cmake_minimum_required(VERSION 2.8)
SET(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "/home/xuec07/code/test/cpp_call_python/install" "/home/xuec07/code/test/cpp_call_python/")


   set(PYTHON_INCLUDE_DIRS "/usr/include/python3.8")
   set(PYTHON_LIBRARIES "/usr/lib/x86_64-linux-gnu/libpython3.8.so")

find_package(test1 REQUIRED)
if(test1_FOUND)
    message(STATUS "test path : ${test1_INCLUDE_DIRS}")
else()
    message(STATUS "test not found!")
endif()

find_package(Python3 COMPONENTS Interpreter Development REQUIRED)
find_package(PythonLibs REQUIRED)
include_directories(${PYTHON_INCLUDE_DIRS})

add_executable(${PROJECT_NAME} test.cpp)

target_link_libraries(${PROJECT_NAME} mytest::test1 ${PYTHON_LIBRARIES})

编译后生成myapp可执行程序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值