0

I'm very new to the whole CMake. Following this and this posts, now I want to call a MAXON function inside Python, using pybind11. What I have done so far:

wget https://www.maxongroup.com/medias/sys_master/root/8837358518302/EPOS-Linux-Library-En.zip
  • unzip:
unzip EPOS-Linux-Library-En.zip
  • make the install shell script executable and run it:
chmod +x ./install.sh
sudo ./install.sh
  • Then going to the example folder:
cd /opt/EposCmdLib_6.6.1.0/examples/HelloEposCmd/
  • Now combining the CMakeLists.txt files from here:
# CMakeLists.txt

cmake_minimum_required(VERSION 2.8.12)
project (HelloEposCmd)

set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Wall")

set(CMAKE_POSITION_INDEPENDENT_CODE ON)

find_package(pybind11 REQUIRED)
pybind11_add_module(${PROJECT_NAME} HelloEposCmd.cpp)

add_executable(${PROJECT_NAME} HelloEposCmd.cpp)

target_link_libraries(${PROJECT_NAME} -lEposCmd)
  • and the HelloEposCmd.cpp this line is added right after other header files:
#include <pybind11/pybind11.h>

the main function is renamed to:

int run(int argc, char** argv)

and the pybind11 syntax to add the module is written at the end:

PYBIND11_MODULE(HelloEposCmd, m) {

    m.def("run", &run, "runs the HelloEposCmd");
}

However, When I run the cmake . I get the error:

CMake Error at CMakeLists.txt:13 (add_executable):

add_executable can not create target "HelloEposCmd" because another target with the same name already exists. The existing target is a module library created in source directory "/opt/EposCmdLib_6.6.1.0/examples/HelloEposCmd" See documentation for policy CMP0002 for more details.

...

I was wondering if you could be kind to help me get the right CMakeList.txt file. Ideally, I should be able to call the compiled module in python:

# HelloEposCmd.py

import HelloEposCmd

HelloEposCmd.run()

Thanks for your support in advance.

Community
  • 1
  • 1
Foad S. Farimani
  • 12,396
  • 15
  • 78
  • 193

2 Answers2

1

pybind11_add_module already creates a target for you. So you don't need add_executable anymore. Just remove that line and when you will build you will get a library with the name HelloEposCmd

add_executable is needed if you are building an executable (.exe), which I believe is not what you want.

Documenation of pybind11 says.

This function behaves very much like CMake’s builtin add_library (in fact, it’s a wrapper function around that command).

abhilb
  • 5,639
  • 2
  • 20
  • 26
  • now I get another error: `CMake Error at CMakeLists.txt:15 (target_link_libraries) the keyword signature ...` – Foad S. Farimani Feb 03 '20 at 11:46
  • you don't need that line too. It is needed to link libraries when your are building an executable. – abhilb Feb 03 '20 at 11:50
  • are you sure?! because when I remove this it compiles but when running the code we get segmentations fault errors. – Foad S. Farimani Feb 03 '20 at 11:51
  • when you build do you get `HelloEposCmd` library? – abhilb Feb 03 '20 at 11:57
  • 1
    check the cmake example from the pybind11 documentation [here](https://github.com/pybind/cmake_example/blob/master/CMakeLists.txt) – abhilb Feb 03 '20 at 11:59
  • removing those two last lines the `cmake .` works. However, when running `make` I get the `error: can not convert ... char**` which has to do with pybind11 as I'm reading [here](https://github.com/pybind/pybind11/issues/417#issuecomment-248150544). I need to find a workaround. for example if I could understand what are the default values for `int argc` and `char** argv` then I could just define them as variables inside the `run` function. – Foad S. Farimani Feb 03 '20 at 12:00
  • as a simple example, I'm actually using my other post [here](https://stackoverflow.com/a/59968956/4999991). – Foad S. Farimani Feb 03 '20 at 12:02
  • 1
    as you pointed out char** is not supported by pybind11. What is it that you want to do with your run function? rewrite the signature of your run function so that it doesn't use char**. btw because the issue is now not related to cmake any more you should close this post – abhilb Feb 03 '20 at 12:07
  • actually I think it is still partly cmake problem. What I did as I suggested above I defined argc and argv as variables inside the run function. except I defined `char* argv[] = {"HelloEposCmd"}` and I get only a warning while compiling. but then when running the python code it errors out that `undefined symbol: VCS_ActiveProfilePositionMode`, which I think is because we did not link against the right maxon library files. – Foad S. Farimani Feb 03 '20 at 12:13
  • solved it. will write another post. tldr the last like of the cmake file should be written according to [this](https://github.com/pybind/pybind11/issues/1527#issuecomment-423652505) – Foad S. Farimani Feb 03 '20 at 12:17
  • how do you think about [this](https://stackoverflow.com/a/60039323/4999991) – Foad S. Farimani Feb 03 '20 at 12:33
0

Thanks to abhilb post and his kind followup in the comments I was able to figure the problem out. well, at least find a temporary workaround:

  • According to this post, the last two lines of the CMakeLists.txt file should change to
# this line can be removed
# add_executable(${PROJECT_NAME} HelloEposCmd.cpp)

target_link_libraries(${PROJECT_NAME} PRIVATE -lEposCmd)
  • and then because according to this post pybind11 doesn't support double pointers we change the run function to:
int run() {

    int argc = 1;
    char* argv[] = {"./HelloEposCmd"};

...
}

which I suppose to be a horrible workaround (inspired by information from this page). Now running cmake ., make and python3 HelloEposCmd.py should work properly (except a small c++ warning!).

P.S.1. Maybe someone could use std::vector<std::string> as suggested here. This idea was proposed here and there are already some answers worth investigating.

P.S.2. Following this discussion, another workaround could be something like:

#include <stdio.h>
#include <stdlib.h>

void myFunc(int argc, char* argv[]) {
    for (int i = 0; i < argc; ++i) {
        printf("%s\n", argv[i]);
    }
}

int run(int argc, long* argv_) {

    char** argv = (char**)malloc(argc * sizeof(char*));

    for (int i = 0; i < argc; ++i) {
        argv[i] = (char*)(argv_[i]);
    }

    myFunc(argc, argv);

    free(argv);

    return 0;
}
Foad S. Farimani
  • 12,396
  • 15
  • 78
  • 193