After successfully compiling a Python/C binding with SIP I wanted to do the same thing with Python/C++. For some reason this doesn't work.
Here's the files:
fib.cpp
#include "fib.h"
int fib1(int n)
{
if (n <= 0) {
return 0;
} else if (n <= 2) {
return 1;
} else {
return fib1(n-1) + fib1(n-2);
}
}
fib.h
int fib1(int n);
fib.sip
%Module fib
%Include fib.h
I run the following command to build the intermediate files:
sip -c . fib.sip
So far everything works.
Now I want to build the .pyd file using distutils.
setup.py
from distutils.core import setup, Extension
import sipdistutils
setup(
name = 'fib',
versione = '1.0',
ext_modules=[
Extension("fib", ["fib.sip", "fib.cpp"]),
],
cmdclass = {'build_ext': sipdistutils.build_ext}
)
I run the following command:
python setup.py build
This fails with the following error:
build\temp.win32-2.7\Release\sipfibcmodule.cpp:29:29: error: 'fib1' was not declared in this scope
error: command 'gcc' failed with exit status 1
What could the problem be? Shouldn't c++ be used as a compiler instead of gcc, by the way?
Any help appreciated!
Kind regards
David
I've found a solution that is good enough: namespaces. Next time I'll read the documentation better. I should also mention that a solution with a Fibonacci class could solve the problem, but I didn't find that to be satisfying.
Below the content of the files can be found.
fib.cpp
#include "fib.h"
namespace test
{
int fib1(int n)
{
if (n <= 0) {
return 0;
} else if (n <= 2) {
return 1;
} else {
return fib1(n-1) + fib1(n-2);
}
}
}
fib.h
namespace test
{
int fib1(int n);
}
fib.sip
%Module fib
namespace test {
%TypeHeaderCode
#include "fib.h"
%End
int fib1(int n);
};
setup.py - nothing was changed
Exactly the same commands as mentioned before were used.
Related
I'm on ubuntu with clang-14/gcc-12 and I have 2 cpp files: MyFun.cpp
export module cppcon;
namespace ns_CppCon {
auto GetWelcomeHelper() { return "Welcome to CppCon 2019!"; }
export auto GetWelcome() { return GetWelcomeHelper();}
}
And UseFun.cpp
// main.cpp
#include<iostream>
import cppcon;
int main(){
std::cout << CppCon::GetWelcome();
return 0;
}
Then under command line:
$ clang++ MyFun.cpp UseFun.cpp -std=c++20 && ./a.out
UseFun.cpp:3:8: fatal error: module 'cppcon' not found
import cppcon;
~~~~~~~^~~~~~
1 error generated.
When did I get wrong, how to solve it?
#include <Python.h>
#include <fstream>
#include <iostream>
#include <string>
#include <filesystem>
#include <sys/types.h>
#include <dirent.h>
static const char * sPythonCode =
"class Test :\n"
" def __init__(self) : \n"
" self.Disc_ = 0. \n"
" def getset(self) : \n"
" self.Disc_ = 7. \n"
" return self.Disc_ \n";
std::string writeFile()
{
static int iFile = 0;
std::string sFileName(std::string("test") + std::to_string(iFile));
std::ofstream out("py/" + sFileName + ".py");
out << sPythonCode;
out.flush();
out.close();
iFile++;
return sFileName;
}
static bool bPythonOpen = false;
#define PYTHONPATHLEN 501
static void _PyInit()
{
if (!Py_IsInitialized())
{
Py_InitializeEx(0);
}
}
void openPython(void)
{
if (!bPythonOpen)
{
const size_t szBufferN = 1000;
char acLoadPath[szBufferN];
const char *pypath = "./py";
_PyInit();
PyRun_SimpleString("import sys");
PyRun_SimpleString("print('python (%d.%d.%d) initialized' % (sys.version_info.major, sys.version_info.minor, sys.version_info.micro))");
PyRun_SimpleString("print('--------------------------')");
snprintf(acLoadPath, szBufferN, "sys.path.append('%s')", pypath);
PyRun_SimpleString(acLoadPath);
bPythonOpen = true;
}
}
PyObject *loadPythonModule(const char *acModule)
{
PyObject *pyModule = NULL;
if (bPythonOpen && acModule && strcmp(acModule, ""))
{
printf("%s\n", acModule);
pyModule = PyImport_ImportModule(acModule);
if (!pyModule)
{
PyErr_Print();
}
}
return pyModule;
}
void loadPython()
{
std::string sFileName = writeFile();
openPython();
//sleep(1);
PyObject *pPythonModule = loadPythonModule(sFileName.c_str());
if (pPythonModule)
PyDict_DelItemString(PyImport_GetModuleDict(), PyModule_GetName((PyObject *)pPythonModule));
}
int main(int argc, char **argv)
{
for (int i = 0; i < 10; i++)
{
loadPython();
}
}
My working env:
gcc version 8.3.1 20190311 (Red Hat 8.3.1-3) (GCC)
Red Hat Enterprise Linux Server release 7.6 (Maipo)
problem with python 3.6.10 / 3.8.3
Command to compile:
g++ pythontest.cpp -I/opt/python/python3.6.10/include/python3.6m -L/opt/python/python3.6.10/lib -lpython3.6m
create py directory:
mkdir py
When I run this code I have random error on different test file that I load.
Example of output:
python (3.6.10) initialized
--------------------------
test0
test1
test2
test3
ModuleNotFoundError: No module named 'test3'
test4
test5
ModuleNotFoundError: No module named 'test5'
test6
test7
ModuleNotFoundError: No module named 'test7'
test8
test9
ModuleNotFoundError: No module named 'test9'
Good to know:
If I uncomment the line with the sleep it works well
If I remove the iFile++, it works also as it used after an already created file
If I relaunch a second without rm -rf py directory it works also
If I erase file after each run in the loadPython function and remove iFile++ it works also
If I use strace to launch the executable I don't see the problem
For the moment it seems that the Python loader does not see the file on disk, however in case of failure if I print what I have in the directory thanks to dirent I see the testx.py
Please note that we reproduce the error on different Linux servers (not a hardware problem and even on Windows), with Python 2.7.x it works perfectly well.
You should call __import__('importlib').invalidate_caches() each time you modify modules folders to let C Python knows it must read directories again.
I am trying to install Catch2 on ubuntu 20.04.
Used instruction from here.
This is what i do:
$ git clone https://github.com/catchorg/Catch2.git
$ cd Catch2
$ cmake -Bbuild -H. -DBUILD_TESTING=OFF
$ sudo cmake --build build/ --target install
Than it saing me that all ok: link for output.
BUT:
When I try to compile the example: // from here
main.cpp
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
#define CATCH_CONFIG_ENABLE_BENCHMARKING
#include <catch2/catch.hpp>
std::uint64_t Fibonacci(std::uint64_t number) {
return number < 2 ? 1 : Fibonacci(number - 1) + Fibonacci(number - 2);
}
TEST_CASE("Fibonacci") {
CHECK(Fibonacci(0) == 1);
// some more asserts..
CHECK(Fibonacci(5) == 8);
// some more asserts..
// now let's benchmark:
BENCHMARK("Fibonacci 20") {
return Fibonacci(20);
};
BENCHMARK("Fibonacci 25") {
return Fibonacci(25);
};
BENCHMARK("Fibonacci 30") {
return Fibonacci(30);
};
BENCHMARK("Fibonacci 35") {
return Fibonacci(35);
};
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(Persistent-world LANGUAGES CXX)
add_executable(${PROJECT_NAME} main.cpp )
find_package(Catch2 REQUIRED)
target_link_libraries(${PROJECT_NAME} Catch2::Catch2)
It output such ERROR: catch2/catch.hpp: No such file or directory
Thanks in advance
The problem is quite simple: clonning catchorg/Catch2 now gets you a v3 branch by default, which works differently. The most important change is that it is no longer single header, and that the catch2/catch.hpp header no longer exists.
You can either switch to the v2 branch before configuring and installing the build, or adapt your code to the changes in v3, starting with this documentation on v2 -> v3 migration.
To get the default main, link against Catch2::Catch2WithMain target.
Admin helped me.
On catch v3. I need:
cmake_minimum_required(VERSION 3.5)
project(Catch2 LANGUAGES CXX)
add_executable(${PROJECT_NAME} main.cpp )
find_package(Catch2)
target_link_libraries(${PROJECT_NAME} Catch2::Catch2WithMain)
If you just link against Catch2::Catch2, you won't get the default main and have to write your own, and your own main needs to invoke the tests. See e.g. that
Than i understand that with main it should looks like:
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
#define CATCH_CONFIG_ENABLE_BENCHMARKING
#include <catch2/catch_all.hpp>
std::uint64_t Fibonacci(std::uint64_t number) {
return number < 2 ? 1 : Fibonacci(number - 1) + Fibonacci(number - 2);
}
TEST_CASE("Fibonacci") {
CHECK(Fibonacci(0) == 1);
// some more asserts..
CHECK(Fibonacci(5) == 8);
// some more asserts..
// now let's benchmark:
BENCHMARK("Fibonacci 20") {
return Fibonacci(20);
};
BENCHMARK("Fibonacci 25") {
return Fibonacci(25);
};
BENCHMARK("Fibonacci 30") {
return Fibonacci(30);
};
BENCHMARK("Fibonacci 35") {
return Fibonacci(35);
};
}
int main( int argc, char* argv[] )
{
Catch::Session session; // There must be exactly one instance
// writing to session.configData() here sets defaults
// this is the preferred way to set them
int returnCode = session.applyCommandLine( argc, argv );
if( returnCode != 0 ) // Indicates a command line error
return returnCode;
// writing to session.configData() or session.Config() here
// overrides command line args
// only do this if you know you need to
int numFailed = session.run();
// numFailed is clamped to 255 as some unices only use the lower 8 bits.
// This clamping has already been applied, so just return it here
// You can also do any post run clean-up here
return numFailed;
}
I would need some help with using ngspice as a library in a webassembly (wasm) project.
I installed emsdk and newest version of emcc (1.39.20) and downloaded the source of ngspice version 32.
To my greatest surprise, I was able to compile ngspice to wasm target by following this guide:
emconfigure ./configure --with-ngshared --disable-debug
emmake make
(I had to patch configure a little to pass the checks by adding .out.js a.out.wasm to this line:)
# The possible output files:
ac_files="a.out a.out.js a.out.wasm conftest.exe conftest a.exe a_out.exe b.out conftest.*"
This produced a libngspice.so.0.0.0 file that I tried to link to from C++ code. However that failed with duplicate symbol: main. So it seemed that libngspice.so.0.0.0 contained a main function, that shouldn't have been there if I understand the purpose of the --with-ngshared of the configure script correctly.
So I manually removed the main function from main.c of ngspice and recomplied using the above method. This time I could successfully complie my own project, linking to ngspice. However when I call ngSpice_Init, I recieve the following runtime errors:
stderr Note: can't find init file.
exception thrown: RuntimeError: unreachable executed,#http://localhost:8001/sim.js line 1802 > WebAssembly.instantiate:wasm-function[67]:0x24e9
#http://localhost:8001/sim.js line 1802 > WebAssembly.instantiate:wasm-function[88]:0x423b
...
Minimal reproducible steps:
compile ngspice as above
compile the code below using em++ -o sim.html sim.cpp lib/libngspice.so
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sharedspice.h"
using namespace std;
int recieve_char(char * str, int id, void* p){
printf("recieved %s\n", str);
}
int recieve_stat(char* status, int id, void* p){
printf("status: %s\n", status);
}
int ngexit(int status, bool unload, bool exit, int id, void* p){
printf("exit: %d\n", status);
}
int recieve_data(vecvaluesall* data, int numstructs, int id, void* p){
printf("data recieved: %f\n", data->vecsa[0]->creal);
}
int recieve_init_data(vecinfoall* data, int id, void* p){
printf("init data recieved from: %d\n", id);
}
int ngrunning(bool running, int id, void* p){
if(running){
printf("ng is running\n");
}else{
printf("ng is not running\n");
}
}
int main(){
ngSpice_Init(&recieve_char, &recieve_stat, &ngexit,
&recieve_data, &recieve_init_data, &ngrunning, (void*)NULL);
char** circarray = (char**)malloc(sizeof(char*) * 7);
circarray[0] = strdup("test array");
circarray[1] = strdup("V1 1 0 1");
circarray[2] = strdup("R1 1 2 1");
circarray[3] = strdup("C1 2 0 1 ic=0");
circarray[4] = strdup(".tran 10u 3 uic");
circarray[5] = strdup(".end");
circarray[6] = NULL;
ngSpice_Circ(circarray);
ngSpice_Command("run");
return 0;
}
So could someone please help me correctly compiling ngspice library to wasm target?
(Before someone asks, yes, I've seen this question, but it didn't help much)
I was able to compile the library and my example code after making several changes to the ngspice source. The patch and a guide on how to compile ngspice to wasm, can be found here.
(The issue leading to the error shown in my question was with the example code, not returning anything from functions that by signature should return int. This is not tolerated in wasm.)
I'm building an embedded python application in C++, using boost::python. The embedded environment exports part of itself as a module, in other words the python code that runs in the environment won't run in a standard python env as the embedded module can't be imported.
One of the features that would be really helpful for debugging would be a debug shell, where I can break out and manually input standard python expressions to inspect/modify the current state. The problem I have is that I don't/can't know in advance whether it's an eval (e.g. "2+2") or an exec (e.g. "a=2+2"). If I exec("2+2") I don't get the result, and if I eval("a=2+2") I get a syntax error. (Coming from a C background I don't quite understand why this distinction exists). Trying eval first, then exec if it fails, seems like a very dubious solution not least because of side effects.
As far as I can see boost::python simply replicates python's eval/exec functions, so this problem is more at the python level, but the answer I'm hoping to get is how to do it at the C++ (ideally boost) level. Is there some horrendously complicated regex that could be used to differentiate exec-able from eval-able code? For now I'm just going with the ugly solution of making the user decide with a prefix on the expression.
Here's an MCVE with a TODO at the point where I need to choose between eval and exec (obv. requires python-dev and boost_python libs)
// g++ $(python3-config --cflags) so.cpp -fPIC -lboost_python3 $(python3-config --ldflags)
#include <boost/python.hpp>
#include <string>
#include <iostream>
namespace py = boost::python;
std::string pyobject_to_string(PyObject* obj)
{
PyObject* repr = PyObject_Str(obj);
PyObject* str = PyUnicode_AsEncodedString(repr, "utf-8", "~E~");
const char *bytes = PyBytes_AS_STRING(str);
Py_XDECREF(repr);
Py_XDECREF(str);
return std::string(bytes);
}
int main(int argc, const char** argv)
{
// Init python env
Py_Initialize();
if (argc < 2)
{
return 1;
}
try
{
// TODO decide, based on argv[1], which needs to be called, this:
py::object res = py::eval(argv[1]);
std::cout << pyobject_to_string(res.ptr()) << std::endl;
// or this:
py::exec(argv[1]);
// or something else entirely...?
}
catch(py::error_already_set&)
{
if (PyErr_Occurred())
{
PyObject *type, *value, *traceback;
PyErr_Fetch(&type, &value, &traceback);
std::string message = pyobject_to_string(type) + ":" + pyobject_to_string(value);
//PyErr_Restore(type, value, traceback);
std::cerr << message << std::endl;
}
else
{
std::cerr << "unknown error" << std::endl;
return 1;
}
}
}
Example output is:
$ ./a.out 2+2
4
$ ./a.out a=2+2
<class 'SyntaxError'>:('invalid syntax', ('<string>', 1, 2, 'a=2+2'))
Many thanks in advance