jupyter-xeus / xeus-cling

Jupyter kernel for the C++ programming language
BSD 3-Clause "New" or "Revised" License
3.01k stars 294 forks source link

How to include a simple header file (not a third-party library) #481

Closed creme332 closed 1 year ago

creme332 commented 1 year ago

My file structure looks like this:

liGebra/
├─ ex.ipynb
├─ src/
│  ├─ SquareMatrix.h
│  ├─ SquareMatrix.cpp

I want to use the SquareMatrix.h file inside my notebook ex.ipynb. I tried:

// cell 1
#pragma cling add_include_path("/home/mcl/githubrepos/liGebra/src/")

// cell 2
#include "SquareMatrix.h"

// cell 3
SquareMatrix A({{10, 1, 2, 3, 30},
                {1, 15, 2, -5, 17},
                {0, 1, 20, 3, 74},
                {3, -10, -1, 25, 80}},
                true);
A.solve_approx(1, {0, 0, 0, 0}, 3);

The first two cells execute without errors but the third one fails due to some linking error:

IncrementalExecutor::executeFunction: symbol '_ZN12SquareMatrix12solve_approxEbSt6vectorIdSaIdEEii' unresolved while linking function '_GLOBAL__sub_I_cling_module_6'!
You are probably missing the definition of SquareMatrix::solve_approx(bool, std::vector<double, std::allocator<double> >, int, int)
Maybe you need to load the corresponding shared library?
IncrementalExecutor::executeFunction: symbol '_ZN12SquareMatrixC1ESt6vectorIS0_IdSaIdEESaIS2_EEb' unresolved while linking function '_GLOBAL__sub_I_cling_module_6'!
You are probably missing the definition of SquareMatrix::SquareMatrix(std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >, bool)
Maybe you need to load the corresponding shared library?
IncrementalExecutor::executeFunction: symbol '_ZN12SquareMatrix9calc_coutEv' unresolved while linking function '_GLOBAL__sub_I_cling_module_6'!
You are probably missing the definition of SquareMatrix::calc_cout()
Maybe you need to load the corresponding shared library?

What I tried

Cell 1 Cell 2 Result
Remove cell #include "/home/mcl/githubrepos/liGebra/src/SquareMatrix.h" Fail
#pragma cling add_include_path("./src/") #include "SquareMatrix.h" Fail
#pragma cling add_include_path("/home/mcl/githubrepos/liGebra/src/") and #pragma cling add_library_path("/home/mcl/githubrepos/liGebra/src/") #include "SquareMatrix.h" Fail

Version

xeus                      3.0.5                hac2b420_0    conda-forge
xeus-cling                0.15.0               h0cdce71_0    conda-forge
xeus-zmq                  1.0.2                h0541b36_1    conda-forge

Any help is appreciated. Thank you.

jonesholger commented 1 year ago

you need to tell cling where to get the symbols you defined in SquareMatrix.cpp, either: 1: compile SquareMatrix.cpp into a .so and load it; put main into separate file. 2: Put code in SquareMatrix.cpp in prior cells (copy/paste), before calling A.solve_approx. There are some issues/workarounds for multiple functions in one cell; just split them up for now.

This all assumes that SquareMatrix.cpp doesn't rely on other third party routines. I just think of it where each cell that executes a function (vs defined) gets wrapped, compiled, linked, executed, and output streamed so you can view result. Basically the same as your normal C++ environ.

creme332 commented 1 year ago

Thank you for your help. I ended up using your first recommendation because my SquareMatrix.cpp file is too large to be broken down into multiple functions to put in separate cells.

SquareMatrix.cpp has no third-party dependencies. I executed the following commands to create a shared library in the same directory as my notebook:

g++ -c -fPIC src/SquareMatrix.cpp -std=c++17
g++ SquareMatrix.o -shared -o libProject.so 

My jupyter notebook then becomes:

#pragma cling load("libProject")
#include "src/SquareMatrix.h"

SquareMatrix A({{10, 1, 2, 3, 30},
                {1, 15, 2, -5, 17},
                {0, 1, 20, 3, 74},
                {3, -10, -1, 25, 80}},
                true);
A.solve_approx(1, {0, 0, 0, 0}, 3);

Then everything executes fine.