In my project, I'm using OCanren package which I installed as described here: https://github.com/JetBrains-Research/OCanren#Installation.
I have a file test.ml where I use OCanren:
open OCanren
let _ = inj
And a dune file in the same directory:
(executable
(name test)
(libraries ocanren mtime mtime.clock.os mtime.clock mtime.top)
(flags (:standard -rectypes)))
This is the problem I have when I try to build an executable:
$ dune build test.exe
File "_none_", line 1:
Error: No implementations provided for the following modules:
Mtime_clock referenced from ~/.opam/4.07.1+fp+flambda/lib/ocanren/OCanren.cmxa(Timer)
Mtime referenced from ~/.opam/4.07.1+fp+flambda/lib/ocanren/OCanren.cmxa(Timer),
~/.opam/4.07.1+fp+flambda/lib/ocanren/OCanren.cmxa(Core)
Done: 19/20 (jobs: 1)(base)
How do I provide the implementations for Mtime_clock and Mtime?
The solution was to put Mtime packages before OCanren in the dune file:
(executable
(name test)
(libraries mtime mtime.clock.os ocanren)
(flags (:standard -rectypes)))
Related
I want to include a module in an OCaml program where the module is not
directly called by the main (or any other) module, but rather does something during
initialization. How do I do that with dune? It seems that dune
only includes modules that are explicitly invoked, even when I list
other modules in a modules stanza.
Example of dune not doing what I want:
Mod1.ml:
let mod1 () : unit =
Printf.printf "in mod1\n"
let () =
mod1 ()
Mod2.ml:
let mod2 () : unit =
Printf.printf "in mod2\n"
let () =
mod2 ()
dune:
(executable
(name Mod1)
(modules
Mod1
Mod2
)
)
dune-project
(lang dune 3.3)
Compiling and running:
$ dune exec ./Mod1.exe
in mod1
My goal is to also see in mod2 above output.
Example that works with direct ocamlc invocation:
This is what I would do if not using dune:
$ ocamlc -o both.exe Mod1.ml Mod2.ml
$ ./both.exe
in mod1
in mod2
Adding an explicit call
If I change Mod1.ml to:
let mod1 () : unit =
Printf.printf "in mod1\n"
let () =
mod1 ();
Mod2.mod2 () (* added *)
Then both modules get included:
$ dune exec ./Mod1.exe
in mod2
in mod1
in mod2
But my goal is include Mod2 in the executable without explicitly
invoking it from Mod1.
empty_module_interface_if_absent does not help
In the documentation for the
executable
stanza, it says:
(empty_module_interface_if_absent) causes the generation of empty
interfaces for every module that does not have an interface file
already. Useful when modules are used solely for their side-effects.
This field is available since the 3.0 version of the Dune language.
However, this does not help. With dune file:
(executable
(name Mod1)
(empty_module_interface_if_absent) ; added
(modules
Mod1
Mod2
)
)
and reverting to the original Mod1.ml, the behavior is the same:
$ dune exec ./Mod1.exe
in mod1
Versions, etc.
$ ocamlc --version
4.14.0
$ dune --version
3.3.1
$ opam --version
2.1.2
$ uname -a
Linux mint201vm 5.4.0-58-generic #64-Ubuntu SMP Wed Dec 9 08:16:25 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
You can pack your modules in a library and then link this library to your main executable using the linkall option. E.g., using your concrete example,
(executable
(name mod1)
(modules mod1)
(libraries libmod2)
(flags -linkall))
(library
(name libmod2)
(modules mod2))
But it is more convenient to pack all modules into a library and move the executable into a separate folder. You can create an empty file for the executable main module or do some initialization in it, e.g.,
$ tree
.
├── dune
├── dune-project
├── mod1.ml
├── mod2.ml
└── run
├── dune
└── main.ml
$ cat dune
(library
(name impl))
$ cat run/dune
(executable
(name main)
(libraries impl)
(flags -linkall))
$ dune exec ./run/main.exe
in mod2
in mod1
Either way, note that by default dune packs modules in a library to prevent name-clashing with other libraries (since OCaml has a flat namespace for compilation units). Therefore to access a module Mod2 in the library Libmod2 you have to say Libmod2.Mod2 (if you're outside of the library). If you want to disable this packing, use (wrapped false) in the library stanza.
I'm setting up a demo project using dune, and want to name the executable "hello-world.exe" instead of "hello_world". If I try to build the project I get an compiler error. How can I declare an executable with hyphens in the filename?
I'm using dune 1.9.3 and OCaml 4.05.0.
dune:
(executable
(name hello-world))
hello-world.ml
let () = print_endline "Hello, World!"
build error
$ dune build hello-world.exe
Info: creating file dune-project with this contents:
| (lang dune 1.9)
ocamlc .hello-world.eobjs/byte/hello-world.{cmi,cmo,cmt} (exit 2)
(cd _build/default && /usr/bin/ocamlc.opt -w #a-4-29-40-41-42-44-45-48-58-59-60-40 -strict-sequence -strict-formats -short-paths -keep-locs -g -bin-annot -I .hello-world.eobjs/byte -no-alias-deps -opaque -o .hello-world.eobjs/byte/hello-world.cmo -c -impl hello-world.ml)
File "hello-world.ml", line 1:
Warning 24: bad source file name: "Hello-world" is not a valid module name.
File "hello-world.ml", line 1:
Error: Some fatal warnings were triggered (1 occurrences)
You need to disable the warning 24:
(executable (name hello-world) (flags (:standard -w -24)))
or just
(executable (name hello-world) (flags (:standard -warn-error -24)))
if you prefer to keep the warning
I am using Grassroot Dicom viewer version 2.8.9 to compile into Emscripten library bc on Windows 10 64-bit platform.
I followed the instruction from this website
emconfigure cmake .
emmake make VERBOSE=1
After that I got library file ending with .a instead of .bc similar to
libgdcmcharls.a libgdcmCommon.a libgdcmDICT.a ....
when I looked into the assembly code for each static library file it starts with
! arch./
instead of
BC
as mention in the tutorial website Note
Some build systems may not properly emit bitcode using the above
procedure, and you may see is not valid bitcode warnings. You can run
file to check if a file contains bitcode (also you can manually check
if the contents start with BC). It is also worth running emmake make
VERBOSE=1 which will print out the commands it runs - you should see
emcc being used, and not the native system compiler. If emcc is not
used, you may need to modify the configure or cmake scripts.
I think this is the problem that I cannot generate libraries with contents start with BC but instead I got ! arch ./ ?
and of course those files cannot be linked from emcc ( cannot find reference error )
error: undefined symbol: _ZN4gdcm11ImageReader8GetImageEv
error: undefined symbol: _ZN4gdcm11ImageReaderC1Ev
error: undefined symbol: _ZN4gdcm11ImageReaderD1Ev
error: undefined symbol: _ZN4gdcm5Trace14GetErrorStreamE
So I modified GDCM CMakefile.txt according to this
if (EMSCRIPTEN)
set(CMAKE_AR "emcc" CACHE)
set(CMAKE_STATIC_LIBRARY_SUFFIX ".bc")
set(CMAKE_C_CREATE_STATIC_LIBRARY "<CMAKE_AR> -o <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_CXX_CREATE_STATIC_LIBRARY "<CMAKE_AR> -o <TARGET> <LINK_FLAGS> <OBJECTS>")
endif()
However, it does not help anything. The "make" still generates .a library files
The command that I compiled my code as follows; I also copy all .a files to the same folder as main.cpp
emcc -std=c++17 -O3 -s WASM=1 -s USE_WEBGL2=1 -s FULL_ES3=1 -s ALLOW_MEMORY_GROWTH=1 -o hello.html -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall', 'cwrap']" --no-heap-copy libgdcmcharls.a libgdcmCommon.a libgdcmDICT.a libgdcmDSED.a libgdcmexpat.a libgdcmIOD.a libgdcmjpeg12.a libgdcmjpeg16.a libgdcmjpeg8.a libgdcmMEXD.a libgdcmMSFF.a libgdcmopenjp2.a libgdcmzlib.a libgdcmuuid.a libsocketxx.a main.cpp ...........
The link is my GDCM 2.8.9 library files. Compiled in Windows10 using
emcmake cmake and finally emmake make ( based on mingw32-make ).
Here is my CMakeCXXCompiler.cmake after calling emconfigure cmake .
set(CMAKE_CXX_COMPILER "C:/workspace/emsdk/emscripten/1.38.14/em++.bat")
set(CMAKE_CXX_COMPILER_ARG1 "")
set(CMAKE_CXX_COMPILER_ID "Clang")
set(CMAKE_CXX_COMPILER_VERSION "6.0.1")
set(CMAKE_CXX_COMPILER_VERSION_INTERNAL "")
set(CMAKE_CXX_COMPILER_WRAPPER "")
set(CMAKE_CXX_STANDARD_COMPUTED_DEFAULT "98")
set(CMAKE_CXX_COMPILE_FEATURES "cxx_std_98;cxx_template_template_parameters;cxx_std_11;cxx_alias_templates;cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_decltype;cxx_decltype_incomplete_return_types;cxx_default_function_template_args;cxx_defaulted_functions;cxx_defaulted_move_initializers;cxx_delegating_constructors;cxx_deleted_functions;cxx_enum_forward_declarations;cxx_explicit_conversions;cxx_extended_friend_declarations;cxx_extern_templates;cxx_final;cxx_func_identifier;cxx_generalized_initializers;cxx_inheriting_constructors;cxx_inline_namespaces;cxx_lambdas;cxx_local_type_template_args;cxx_long_long_type;cxx_noexcept;cxx_nonstatic_member_init;cxx_nullptr;cxx_override;cxx_range_for;cxx_raw_string_literals;cxx_reference_qualified_functions;cxx_right_angle_brackets;cxx_rvalue_references;cxx_sizeof_member;cxx_static_assert;cxx_strong_enums;cxx_thread_local;cxx_trailing_return_types;cxx_unicode_literals;cxx_uniform_initialization;cxx_unrestricted_unions;cxx_user_literals;cxx_variadic_macros;cxx_variadic_templates;cxx_std_14;cxx_aggregate_default_initializers;cxx_attribute_deprecated;cxx_binary_literals;cxx_contextual_conversions;cxx_decltype_auto;cxx_digit_separators;cxx_generic_lambdas;cxx_lambda_init_captures;cxx_relaxed_constexpr;cxx_return_type_deduction;cxx_variable_templates;cxx_std_17")
set(CMAKE_CXX98_COMPILE_FEATURES "cxx_std_98;cxx_template_template_parameters")
set(CMAKE_CXX11_COMPILE_FEATURES "cxx_std_11;cxx_alias_templates;cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_decltype;cxx_decltype_incomplete_return_types;cxx_default_function_template_args;cxx_defaulted_functions;cxx_defaulted_move_initializers;cxx_delegating_constructors;cxx_deleted_functions;cxx_enum_forward_declarations;cxx_explicit_conversions;cxx_extended_friend_declarations;cxx_extern_templates;cxx_final;cxx_func_identifier;cxx_generalized_initializers;cxx_inheriting_constructors;cxx_inline_namespaces;cxx_lambdas;cxx_local_type_template_args;cxx_long_long_type;cxx_noexcept;cxx_nonstatic_member_init;cxx_nullptr;cxx_override;cxx_range_for;cxx_raw_string_literals;cxx_reference_qualified_functions;cxx_right_angle_brackets;cxx_rvalue_references;cxx_sizeof_member;cxx_static_assert;cxx_strong_enums;cxx_thread_local;cxx_trailing_return_types;cxx_unicode_literals;cxx_uniform_initialization;cxx_unrestricted_unions;cxx_user_literals;cxx_variadic_macros;cxx_variadic_templates")
set(CMAKE_CXX14_COMPILE_FEATURES "cxx_std_14;cxx_aggregate_default_initializers;cxx_attribute_deprecated;cxx_binary_literals;cxx_contextual_conversions;cxx_decltype_auto;cxx_digit_separators;cxx_generic_lambdas;cxx_lambda_init_captures;cxx_relaxed_constexpr;cxx_return_type_deduction;cxx_variable_templates")
set(CMAKE_CXX17_COMPILE_FEATURES "")
set(CMAKE_CXX20_COMPILE_FEATURES "")
set(CMAKE_CXX_PLATFORM_ID "emscripten")
set(CMAKE_CXX_SIMULATE_ID "")
set(CMAKE_CXX_SIMULATE_VERSION "")
set(CMAKE_AR "C:/workspace/emsdk/emscripten/1.38.14/emar.bat")
set(CMAKE_CXX_COMPILER_AR "C:/Program Files/LLVM/bin/llvm-ar.exe")
set(CMAKE_RANLIB "C:/workspace/emsdk/emscripten/1.38.14/emranlib.bat")
set(CMAKE_CXX_COMPILER_RANLIB "C:/Program Files/LLVM/bin/llvm-ranlib.exe")
set(CMAKE_LINKER "C:/Program Files/LLVM/bin/wasm-ld.exe")
set(CMAKE_COMPILER_IS_GNUCXX )
set(CMAKE_CXX_COMPILER_LOADED 1)
set(CMAKE_CXX_COMPILER_WORKS TRUE)
set(CMAKE_CXX_ABI_COMPILED )
set(CMAKE_COMPILER_IS_MINGW )
set(CMAKE_COMPILER_IS_CYGWIN )
if(CMAKE_COMPILER_IS_CYGWIN)
set(CYGWIN 1)
set(UNIX 1)
endif()
set(CMAKE_CXX_COMPILER_ENV_VAR "CXX")
if(CMAKE_COMPILER_IS_MINGW)
set(MINGW 1)
endif()
set(CMAKE_CXX_COMPILER_ID_RUN 1)
set(CMAKE_CXX_IGNORE_EXTENSIONS inl;h;hpp;HPP;H;o;O;obj;OBJ;def;DEF;rc;RC)
set(CMAKE_CXX_SOURCE_FILE_EXTENSIONS C;M;c++;cc;cpp;cxx;mm;CPP)
set(CMAKE_CXX_LINKER_PREFERENCE 30)
set(CMAKE_CXX_LINKER_PREFERENCE_PROPAGATES 1)
# Save compiler ABI information.
set(CMAKE_CXX_SIZEOF_DATA_PTR "4")
set(CMAKE_CXX_COMPILER_ABI "")
set(CMAKE_CXX_LIBRARY_ARCHITECTURE "")
if(CMAKE_CXX_SIZEOF_DATA_PTR)
set(CMAKE_SIZEOF_VOID_P "${CMAKE_CXX_SIZEOF_DATA_PTR}")
endif()
if(CMAKE_CXX_COMPILER_ABI)
set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_CXX_COMPILER_ABI}")
endif()
if(CMAKE_CXX_LIBRARY_ARCHITECTURE)
set(CMAKE_LIBRARY_ARCHITECTURE "")
endif()
set(CMAKE_CXX_CL_SHOWINCLUDES_PREFIX "")
if(CMAKE_CXX_CL_SHOWINCLUDES_PREFIX)
set(CMAKE_CL_SHOWINCLUDES_PREFIX "${CMAKE_CXX_CL_SHOWINCLUDES_PREFIX}")
endif()
set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "")
set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "")
set(CMAKE_CXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "")
Finally I found the problem. The library that generated from command;
emconfigure cmake .
is not the emcc compatible even when I see the compiler it used em++.bat as the compiler.
How to spot the problem.
I use a program called "Hex Editor Neo" to open the library files ( use only small library files to test, big library files the program crashes).
If it is not compatible to use with emcc. The first few character will be ! arch This will not work. see the picture below for the library file that is wrong generated from cmake;
Make sure that you have BC like in the picture below;
but how to do this
you cannot just use
emconfigure cmake . <---------- wrong
you need to put an option to generate bitcode (.bc) by following command
emconfigure cmake . -DEMSCRIPTEN_GENERATE_BITCODE_STATIC_LIBRARIES=1
Then it will generate all library files ending with .bc and these library files can be linked with emcc
I have a R package that I'm working on that contains code written in C and C++ under the src folder. Currently, the package compiles and works on Rstudio as it follows the default directory structure. As the project builds, I want to be able to organize my code under src, within subfolders. Following directions from "Writing R extensions" - Compiling under sub-directories, I have made a folder called 'test'(/src/test) which now contains all my files(*.c, *.cpp, *.h) and modified my Makevars like so -
SOURCES_C = $(wildcard test/*.c)
SOURCES_CPP = $(wildcard test/*.cpp)
PKG_CPPFLAGS= -I${R_HOME}/include -I.
PKG_LIBS = -L${R_HOME}/lib
CXX_STD = CXX11
OBJECTS =$(SOURCES_CPP:.cpp=.o) $(SOURCES_C:.c=.o)
all : $(SHLIB)
#PKG_CFLAGS= -Wall
clean : rm -f *.o
I want to be able to compile the program in this state, where the C/C++ files are under subfolders inside src. Using the aforementioned Makevars -> the separate object files are being built from the test folder with the correct flags and compiler, for all C/CPP files. However, there are some discrepancies with the build command for the shared object. This is the log when compiling the files under src/test which fails with an undefined symbol error.
gcc -std=gnu99 -shared -L/usr/local/lib64 -o BioCro.so test/BBox.o test/Climate.o test/Compound.o test/Grid.o test/LeafOptics.o test/Maths.o test/Normal.o test/Point3D.o test/Ray.o test/Triangle.o test/Vector3D.o test/runFastTracer.o test/Assigncropcent.o test/AuxBioCro.o test/AuxCropGro.o test/AuxMaizeGro.o test/AuxcaneGro.o test/Auxcropcent.o test/AuxwillowGro.o test/BioCro.o test/CalculateBiogeochem.o test/Calculate_Soil_Layer_Temperature.o test/CanA.o test/CanAC_3D.o test/Century.o test/Copy_CropCent_To_DayCent_Structure.o test/Copy_SoilWater_BioCro_To_CropCent.o test/CropGro.o test/CropGro_c.o test/Filling_BioCro_SoilStructure.o test/assignManagement.o test/c3CanA.o test/c3EvapoTrans.o test/c3photo.o test/c4photo.o test/caneGro.o test/createNULLc3tree.o test/cropcent.o test/dailywillow.o test/denitrify.o test/diffusiv.o test/eC4photo.o test/getIdirIdiff.o test/getsoilprop.o test/leachdly.o test/maizeGro.o test/methane.o test/microclimate_for_3Dcanopy.o test/nitrify.o test/nox_pulse.o test/pi_funcs.o test/printcropcentoutput.o test/test_mainC.o test/tgmodel.o test/tracegas.o test/update_3Dcanopy_structure.o test/wfps.o test/willowCent.o test/willowGro.o -L/usr/local/R-3.1.0/lib64/R/lib -L/usr/local/R-3.1.0/lib64/R/lib -lR
installing to /home/vashist1/R/x86_64-unknown-linux-gnu-library/3.1/BioCro/
** R
** data
** inst
** preparing package for lazy loading
** help
*** installing help indices
** building package indices
** installing vignettes
** testing if installed package can be loaded
Error in dyn.load(file, DLLpath = DLLpath, ...) :
unable to load shared object '/home/vashist1/R/x86_64-unknown-linux-gnu-library/3.1/BioCro/libs/BioCro.so':
/home/vashist1/R/x86_64-unknown-linux-gnu-library/3.1/BioCro/libs/BioCro.so:
undefined symbol: _ZTVN10__cxxabiv117__class_type_infoE
Error: loading failed
Compared with the successful log which builds successfully!
g++ -shared -L/usr/local/lib64 -o BioCro.so Assigncropcent.o AuxBioCro.o AuxCropGro.o AuxMaizeGro.o AuxcaneGro.o Auxcropcent.o AuxwillowGro.o BBox.o BioCro.o CalculateBiogeochem.o Calculate_Soil_Layer_Temperature.o CanA.o CanAC_3D.o Century.o Climate.o Compound.o Copy_CropCent_To_DayCent_Structure.o Copy_SoilWater_BioCro_To_CropCent.o CropGro.o CropGro_c.o Filling_BioCro_SoilStructure.o Grid.o LeafOptics.o Maths.o Normal.o Point3D.o Ray.o Triangle.o Vector3D.o assignManagement.o c3CanA.o c3EvapoTrans.o c3photo.o c4photo.o caneGro.o createNULLc3tree.o cropcent.o dailywillow.o denitrify.o diffusiv.o eC4photo.o getIdirIdiff.o getsoilprop.o leachdly.o maizeGro.o methane.o microclimate_for_3Dcanopy.o nitrify.o nox_pulse.o pi_funcs.o printcropcentoutput.o runFastTracer.o test_mainC.o tgmodel.o tracegas.o update_3Dcanopy_structure.o wfps.o willowCent.o willowGro.o -L/usr/local/R-3.1.0/lib64/R/lib -lR
installing to /home/vashist1/R/x86_64-unknown-linux-gnu-library/3.1/BioCro/libs
1) The shared object compiles using g++ under default conditions, whereas under subdirectory conditions the compiler used is gcc. Can I change that behaviour via Makevars?
2) Further research allowed me to find that the undefined symbol error is a linking error fixed by the -L/-l flag. However, the -L flag is the same for both build commands. Is there any other library I am failing to link which is linked by default?
I ran into the same issue. Looking at the example of the RSiena package mentioned as an example in "Writing R Extensions" section 1.2.1.3 I noticed that that package still has some .cpp files not in a subdirectory. So I added a dummy.cpp file in src/ with the following contents:
void dummy (void)
{
}
After this g++ was correctly used for the linking step and the .so file was created as expected.
In my case it turns out that I don't need to change the Makevars files as I first mentioned in my answer. Even without the change below (so only having the dummy.cpp file present in src/) linking is done correctly.
I'll leave it in in case it may help someone else with a (slightly) different setup.
And add the corresponding .o file in the list of $(OBJECTS) variable in the Makevars file:
OBJECTS = $(SOURCES:.cpp=.o) dummy.o
Sorry for such a general title, but i'm not quite sure what exactly i'm missing or what i'm doing wrong. My aim is to build a python extension using boost.python under cygwin and avoiding boost.build tools, that is using make instead of bjam. The latter way was working for me quite good, but now i want to do it this way. I solved many issues by googling and looking for similar topics and that helped me to figure out some tricks and to move forward. Yet at the last step there seems to be some problem. I'll try to describe all my steps in some details in hope that this post may be useful to others in the future and also to better describe the setup.
Because i was not quite sure about the original (from various cygwin repositories) installations of both python and boost i decided to install them from scratch in my home directory, so here is what i do:
first install python. I'll skip the details for this, it is more-or-less straightforward.Important for the latter description is just the path:
/home/Alexey_2/Soft/python2.6 - this is PYTHONPATH, also included in PATH
working on boost:
a) unpack boost source into
/home/Alexey_2/Soft/boost_1_50_0 - this is BOOST_ROOT
b) making bjam. first go into directory:
/home/Alexey_2/Soft/boost_1_50_0/tools/build/v2
next, invoke bootstrap.sh this eventually creates b2 and bjam executables in this directory. In .bash_profile add this directory to PATH, so we can call bjam. Here and after each future edits of .bash_profile i restart cygwin to make the changes
come to the effect
c) still in the
/home/Alexey_2/Soft/boost_1_50_0/tools/build/v2
directory - edit user-config.jam, to let bjam know which python to use. So in my case i only add one line:
using python : 2.6 : /home/Alexey_2/Soft/python2.6/bin/python2.6 : /home/Alexey_2/Soft/python2.6/include/python2.6 : /home/Alexey_2/Soft/python2.6/bin ;
in the lib-path (last entry) i put /home/Alexey_2/Soft/python2.6/bin because it contains libpython2.6.dll
d) ok. now we can make boost-python libraries. go to BOOST_ROOT directory and execute command
bjam --with-python toolset=gcc link=shared
this creates necessary libraries (cygboost_python.dll and libboost_python.dll.a) and places them into
/home/Alexey_2/Soft/boost_1_50_0/stage/lib
building python extension.
here is my simple test program (actually part of the example code)
// file xyz.cpp
#include <boost/python.hpp>
#include <iostream>
#include <iomanip>
using namespace std;
using namespace boost::python;
class Hello
{
std::string _msg;
public:
Hello(std::string msg){_msg = msg;}
void set(std::string msg) { this->_msg = msg; }
std::string greet() { return _msg; }
};
BOOST_PYTHON_MODULE(xyz)
{
class_<Hello>("Hello", init<std::string>())
.def("greet", &Hello::greet)
.def("set", &Hello::set)
;
}
And here is the Makefile:
FLAGS= -fno-for-scope -O2 -fPIC
CPP=c++
# BOOST v 1.50.0
p1=/home/Alexey_2/Soft/boost_1_50_0
pl1=/home/Alexey_2/Soft/boost_1_50_0/stage/lib
# PYTHON v 2.6
p2=/home/Alexey_2/Soft/python2.6/include/python2.6
pl2=/home/Alexey_2/Soft/python2.6/bin
I=-I${p1} -I${p2}
L=-L${pl1} -lboost_python -L${pl2} -lpython2.6
all: xyz.so
xyz.o: xyz.cpp
${CPP} ${FLAGS} ${I} -c xyz.cpp
xyz.so: xyz.o
${CPP} ${FLAGS} -shared -o xyz.so xyz.o ${L}
clean:
rm *.o
rm xyz.so
Some comments:
library paths are set and i compile against proper libraries (see more: compile some code with boost.python by mingw in win7-64bit ).
The link above explains why it is important to configure user-config.jam - i did it in step 1c.
To avoid possible problems (as mentioned in above link and also in Cannot link boost.python with mingw (although for mingw) ) with boost.python libraries liked statically i use
link=shared
as the argument to bjam (see 1d)
As explained here: MinGW + Boost: undefined reference to `WSAStartup#8' the libraries with which one wants to compile something should be listed after object files, that is why we have:
${CPP} ${FLAGS} -shared -o xyz.so xyz.o ${L}
and not
${CPP} ${FLAGS} -shared ${L} -o xyz.so xyz.o
And here is a piece of my .bash_profile (eventually), where i define environmental variables:
# Python
export PATH=/home/Alexey_2/Soft/python2.6/bin:$PATH
export PYTHONPATH=/home/Alexey_2/Soft/python2.6
export LD_LIBRARY_PATH=/home/Alexey_2/Soft/python2.6/lib:/home/Alexey_2/Soft/python2.6/bin:$LD_LIBRARY_PATH
# Boost
export BOOST_ROOT=/home/Alexey_2/Soft/boost_1_50_0
export LD_LIBRARY_PATH=/home/Alexey_2/Soft/boost_1_50_0/stage/lib:$LD_LIBRARY_PATH
export PATH=/home/Alexey_2/Soft/boost_1_50_0/stage/lib:$PATH
# bjam
export PATH=/home/Alexey_2/Soft/boost_1_50_0/tools/build/v2:$PATH
Finally, to the problem. With the above setup i was able to successfully build the python extension object file:
xyz.so
However, when i test it by simple script:
# this is a test.py script
import xyz
the ImportError comes:
$ python test.py
Traceback (most recent call last):
File "test.py", line 1, in <module>
import xyz
ImportError: No module named xyz
It has been noted that the reason for such a problem may be the wrong python executable being used, but this is not the case:
$ which python
/home/Alexey_2/Soft/python2.6/bin/python
what is expected (note python is a symbolic link to python2.6 from that directory)
Here is one more useful piece of information i have:
$ ldd xyz.so
ntdll.dll => /cygdrive/c/Windows/SysWOW64/ntdll.dll (0x76fa0000)
kernel32.dll => /cygdrive/c/Windows/syswow64/kernel32.dll (0x76430000)
KERNELBASE.dll => /cygdrive/c/Windows/syswow64/KERNELBASE.dll (0x748e0000)
cygboost_python.dll => /home/Alexey_2/Soft/boost_1_50_0/stage/lib/cygboost_python.dll (0x70cc0000)
cygwin1.dll => /usr/bin/cygwin1.dll (0x61000000)
cyggcc_s-1.dll => /usr/bin/cyggcc_s-1.dll (0x6ff90000)
cygstdc++-6.dll => /usr/bin/cygstdc++-6.dll (0x6fa90000)
libpython2.6.dll => /home/Alexey_2/Soft/python2.6/bin/libpython2.6.dll (0x67ec0000)
??? => ??? (0x410000)
I'm wondering what
??? => ??? (0x410000)
could possibly mean. May be this what i'm missing. But what is that?
Any comments and suggestions (not only about the last question) are very much appreciated.
EDIT:
Following suggestion of (twsansbury) examining the python module search path with -vv option:
python -vv test.py
gives
# trying /home/Alexey_2/Programming/test/xyz.dll
# trying /home/Alexey_2/Programming/test/xyzmodule.dll
# trying /home/Alexey_2/Programming/test/xyz.py
# trying /home/Alexey_2/Programming/test/xyz.pyc
...
# trying /home/Alexey_2/Soft/python2.6/lib/python2.6/site-packages/xyz.dll
# trying /home/Alexey_2/Soft/python2.6/lib/python2.6/site-packages/xyzmodule.dll
# trying /home/Alexey_2/Soft/python2.6/lib/python2.6/site-packages/xyz.py
# trying /home/Alexey_2/Soft/python2.6/lib/python2.6/site-packages/xyz.pyc
Traceback (most recent call last):
File "test.py", line 1, in <module>
import xyz
ImportError: No module named xyz
The first directory is wherefrom i call python to run the script. The main conclusion is that cygwin python is looking for modules (libraries) with the standard Windows extension - dll (among other 3 types), not the .so as i originally expected from the Linux-emulation-style of cygwin. So changing the following lines in the previous Makefile to:
all: xyz.dll
xyz.o: xyz.cpp
${CPP} ${FLAGS} ${I} -c xyz.cpp
xyz.dll: xyz.o
${CPP} ${FLAGS} -shared -o xyz.dll xyz.o ${L}
clean:
rm *.o
rm xyz.dll
produces xyz.dll, which can successfully be loaded:
python -vv test.py
now gives:
Python 2.6.8 (unknown, Mar 21 2013, 17:13:04)
[GCC 4.5.3] on cygwin
Type "help", "copyright", "credits" or "license" for more information.
# trying /home/Alexey_2/Programming/test/xyz.dll
dlopen("/home/Alexey_2/Programming/test/xyz.dll", 2);
import xyz # dynamically loaded from /home/Alexey_2/Programming/test/xyz.dll
ThatImportError is generally not Boost.Python related. Rather, it normally indicates that xyz is not in the Python Module Search Path.
To debug this, consider running python with -vv arguments. This will cause python to print a message for each file that is checked for when trying to import xyz. Regardless, the build process look correct, so the problem is likely the result of either the file extension or the module is not in the search path.
I am unsure as to how Cygwin will interact with Python's run-time loading behavior. However:
On Windows, python extensions have a .pyd extension.
On Linux, python extensions have a .so extension.
Additionally, verify that the xyz library is located in one of the following:
The directory containing the test.py script (or the current directory).
A directory listed in the PYTHONPATH environment variable.
The installation-dependent default directory.
If the unresolved library shown in ldd causes errors, it will generally manifest as an ImportError with a message indicating undefined references.