I am trying install some Python modules in my system using f2py, which are related to an ocean model (in Fortran 90). I am facing some problems with f2py. To be specific, the f2py is unable to link with the NetCDF library even though I have the required library and include files installed. I am using Python 2.7 with Anaconda 2 on Ubuntu16.04 on a 64-bit machine. I'm using gfortran.
To test it's working, I wrote a small code - an f90 module that contains a small subroutine. The subroutine performs a basic math task, and calls a NetCDF routine that prints the NetCDF version installed. The module (testsub.f90) is as follows:
module testsub
implicit none
contains
subroutine f_sum(a, b, s)
!#include 'netcdf.inc'
use netcdf
real(8) :: a, b, s
s = a+b;
!Calls a function that prints the netcdf version
write(*,*) trim(nf90_inq_libvers())
end subroutine f_sum
end module
The makefile for testsub is:
#Fortran compiler
FC=gfortran
NCLIB = -L/home/sonaljit/anaconda2/lib -lnetcdf -lnetcdff -L/usr/lib/python2.7/config-x86_64-linux-gnu -lpython2.7
NCINC = -I/home/sonaljit/anaconda2/include
#f2py and flags
F2PY = /home/sonaljit/anaconda2/bin/f2py
PYFLAGS = "-fPIC -g -O2 -fdefault-real-8"
pytest : testsub.f90
$(F2PY) --fcompiler=$(FC) --f90flags=$(PYFLAGS) -c $(NCINC) -m testpymod testsub.f90 $(NCLIB)
clean :
rm testpymod.so
I have the NetCDF library and include files installed in the given paths. When I run the makefile using make pytest, I get the following error:
/usr/bin/ld: /home/sonaljit/anaconda2/lib/libnetcdf.a(netcdf.o): relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
/home/sonaljit/anaconda2/lib/libnetcdf.a: error adding symbols: Bad value
collect2: error: ld returned 1 exit status
However, I am not seeing this error when I am commenting out the NetCDF lines in the module. It seems f2py is not able to link to NetCDF routines. What can be the error here? Is it due to the structure of the code? Or, do I need to include some other library?
You are compiling a shared (dynamic) library and you should use a shared library version of NetCDF.
If you installed NetCDF yourself (as suggested by the path in your /home/sonaljit), you should install the .so version and link with this version.
Related
Describe what happened:
For context, i am currently trying to embed python into golang. I came across this module go-python3 and decided to use it. I was originally using the python3.7 variant of the module then decided to upgrade my python version from 3.7 to 3.8.
Read: https://github.com/go-python/cpy3/issues/29#issuecomment-1321199010
I replaced python3.pc in pkgconfig with python-3.8.pc and got the following error when trying to run:
protoc -Isrc/proto --go_opt=module=grpc-golang --go_out=. --go-grpc_opt=module=grpc-golang --go-grpc_out=. src/proto/*.proto
go build -o dest/server ./src/server && PYTHONPATH=.
# grpc-golang/src/server
/usr/local/go/pkg/tool/linux_amd64/link: running gcc failed: exit status 1
/usr/bin/ld: /tmp/go-link-2733155445/go.o:(.data+0x78): undefined reference to `PyBool_Type'
/usr/bin/ld: /tmp/go-link-2733155445/go.o:(.data+0x80): undefined reference to `PyByteArray_Type'
/usr/bin/ld: /tmp/go-link-2733155445/go.o:(.data+0x88): undefined reference to `PyBytes_Type'
/usr/bin/ld: /tmp/go-link-2733155445/go.o:(.data+0x90): undefined reference to `PyComplex_Type'
/usr/bin/ld: /tmp/go-link-2733155445/go.o:(.data+0x98): undefined reference to `PyDict_Type'
/usr/bin/ld: /tmp/go-link-2733155445/go.o:(.data+0xa0): undefined reference to `PyExc_ArithmeticError'
/usr/bin/ld: /tmp/go-link-2733155445/go.o:(.data+0xa8): undefined reference to `PyExc_AssertionError'
/usr/bin/ld: /tmp/go-link-2733155445/go.o:(.data+0xb0): undefined reference to `PyExc_AttributeError'
/usr/bin/ld: /tmp/go-link-2733155445/go.o:(.data+0xb8): undefined reference to `PyExc_BaseException'
/usr/bin/ld: /tmp/go-link-2733155445/go.o:(.data+0xc0): undefined reference to `PyExc_BlockingIOError'
/usr/bin/ld: /tmp/go-link-2733155445/go.o:(.data+0xc8): undefined reference to `PyExc_BrokenPipeError'
/usr/bin/ld: /tmp/go-link-2733155445/go.o:(.data+0xd0): undefined reference to `PyExc_BufferError'
:
This are some of the details:
>> python3 --version
3.8.10
>> pkg-config --cflags --libs python3
-I/usr/include/python3.8 -I/usr/include/x86_64-linux-gnu/python3.8
>> echo $PKG_CONFIG_PATH
/usr/lib/x86_64-linux-gnu/pkgconfig/
>> pkg-config --list-all
python-3.8 Python - Build a C extension for Python
zlib zlib - zlib compression library
protobuf-lite Protocol Buffers - Google's Data Interchange Format
bash-completion bash-completion - programmable completion for the bash shell
xkeyboard-config XKeyboardConfig - X Keyboard configuration data
protobuf Protocol Buffers - Google's Data Interchange Format
systemd systemd - systemd System and Service Manager
libdmmp libdmmp - Device mapper multipath management library
python3 Python - Build a C extension for Python
libxcrypt libxcrypt - Extended crypt library for DES, MD5, Blowfish and others
udev udev - udev
shared-mime-info shared-mime-info - Freedesktop common MIME database
python-3.8-embed Python - Embed Python into an application
expat expat - expat XML parser
python3-embed Python - Embed Python into an application
libcrypt libxcrypt - Extended crypt library for DES, MD5, Blowfish and others
Describe what you expected:
Should be able to work fine, like its 3.7 variant.
I ran into a similar problem just recently. After searching through a few forums on embedding python, I ran into this one: "Embedding Python in C, linking fails with undefined reference to `Py_Initialize'" 1. I wasn't entirely sure how to do this at first in golang, but I had been doing other online searches on embedded python in golang. Going back through these, I landed at an article call, "Python and Go : Part IV - Using Python in Memory" 2, where it describes in the "Building" section how to specify specific flags to be use in the C building process. Basically, it shows that you can define flags in one of files as such:
/*
#cgo pkg-config: python3
#cgo LDFLAGS: -L/usr/local/lib/python3.8/config-3.8-x86_64-linux-gnu -L/usr/local/lib -lpython3.8 -lcrypt -ldl -lm -lm
#include "Python.h"
*/
import "C"
Although, according to Python's documentation on compiling a python interpreter embedded in another application, you should get the LDFLAGS via,
python3.7-config --ldflags
for python versions <= 3.7 (I don't know how far back if goes. Also, replace the "python3.7-config" accordingly), or,
python3.10-config --ldflags --embed
for python versions > 3.7 (And once again, replace the "python3.10-config" part with the desired python version)
I then thought to myself, "A version of this header is probably located somewhere in the go-python project and it just needs to be changed", so after looking around, I found this header in the high_level_layer.go file in the project and modified it to match what's shown above.
What's exactly going on here is that golang has native functionality with C, so libraries written in C can work in golang, and the opposite is also true (with enough finagling). There's plenty of articles on this functionality. Here's one from go's official website, 3. And since the base python interpreter is written in C, its header and object files can be referenced at compile time by the golang compiler if the linker flags and other flags are set correctly, so that's exactly what's being specified above.
Also, on a different note, I've tried compiling with a few different go compilers. I've had success with the compiler for versions 1.15.5 and 1.18.1, but haven't with 1.19.5. I don't know what's exactly happening, but I'm not going to try and figure it out right now since all I need currently are features in compiler versions >= 1.18. Lastly, I actually had basically the same problems with python3.7, and these changes fixed these problems too...
The scikit-build distribution provides usage examples of FindF2PY and UseF2PY, but they are incomplete, only providing a partial CMakeLists.txt file without the other required files. Based on the documentation I have not been able to make something that builds.
Following the examples in the scikit-build documentation, I created the following files:
CMakeLists.txt:
cmake_minimum_required(VERSION 3.10.2)
project(skbuild_test)
enable_language(Fortran)
find_package(F2PY REQUIRED)
add_f2py_target(f2py_test f2py_test.f90)
add_library(f2py_test MODULE f2py_test.f90)
install(TARGETS f2py_test LIBRARY DESTINATION f2py_test)
setup.py:
import setuptools
from skbuild import setup
requires=['numpy']
setup(
name="skbuild-test",
version='0.0.1',
description='Performs line integrals through SAMI3 grids',
author='John Haiducek',
requires=requires,
packages=['f2py_test']
)
f2py_test.f90:
module mod_f2py_test
implicit none
contains
subroutine f2py_test(a,b,c)
real(kind=8), intent(in)::a,b
real(kind=8), intent(out)::c
end subroutine f2py_test
end module mod_f2py_test
In addition, I created a directory f2py_test containing an empty init.py.
The output from python setup.py develop shows that scikit-build invokes CMake and compiles my Fortran code. However, it fails to find Python.h while compiling the f2py wrapper code:
[2/7] Building C object CMakeFiles/_f2...kages/numpy/f2py/src/fortranobject.c.o
FAILED: CMakeFiles/_f2py_runtime_library.dir/venv/lib/python3.8/site-packages/numpy/f2py/src/fortranobject.c.o
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc -O3 -DNDEBUG -arch x86_64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk -mmacosx-version-min=10.14 -MD -MT CMakeFiles/_f2py_runtime_library.dir/venv/lib/python3.8/site-packages/numpy/f2py/src/fortranobject.c.o -MF CMakeFiles/_f2py_runtime_library.dir/venv/lib/python3.8/site-packages/numpy/f2py/src/fortranobject.c.o.d -o CMakeFiles/_f2py_runtime_library.dir/venv/lib/python3.8/site-packages/numpy/f2py/src/fortranobject.c.o -c ../../../venv/lib/python3.8/site-packages/numpy/f2py/src/fortranobject.c
In file included from ../../../venv/lib/python3.8/site-packages/numpy/f2py/src/fortranobject.c:2:
../../../venv/lib/python3.8/site-packages/numpy/f2py/src/fortranobject.h:7:10: fatal error: 'Python.h' file not found
#include "Python.h"
^~~~~~~~~~
1 error generated.
First caveat, there may be a better way to do this, as I just figured out how to make scikit-build work by stumbling on your post and looking at documentation. Second caveat, I'm also learning cmake. So, there may be a better way.
There are a couple of things that you'll need to make your example here work. The big one is the second argument of add_f2py_target() isn't the source file. It is either the name of a pre-generated *.pyf, or to let f2py generate one, provide it an argument without the *.pyf extension. The other is adding the include directories for various components.
I made your example work with the following CMakeLists.txt:
cmake_minimum_required(VERSION 3.10.2)
project(skbuild_test)
enable_language(Fortran)
find_package(F2PY REQUIRED)
find_package(PythonLibs REQUIRED)
find_package(Python3 REQUIRED COMPONENTS NumPy)
#the following command either generates or points to an existing .pyf
#if provided an argument with .pyf extension, otherwise f2py generates one (not source code).
add_f2py_target(f2py_test f2py_test)
add_library(f2py_test MODULE f2py_test.f90)
include_directories(${PYTHON_INCLUDE_DIRS})
include_directories(${_Python3_NumPy_INCLUDE_DIR})
target_link_libraries(f2py_test ${PYTHON_LIBRARIES})
install(TARGETS f2py_test LIBRARY DESTINATION f2py_test)
I'm trying to compile some C++ code into a dll to import into Python for the first time. I want to be able to return a Numpy array from one of the functions, with an example line that looks like lNumpyArray = PyArray_SimpleNewFromData( 2, lDimensions, NPY_UINT8, (void*)lImage->GetDataPointer() );
At the start of the code I have included Python.h and arrayobject.h.
Using GCC (working on Windows) I have been able to compile the code to a .O file without errors. However, when trying to go to a dll, I'm getting a lot of errors like undefined reference to '__imp__Py_Dealloc'. From my limited understanding, it might be because I'm missing a library somewhere in the linker. Is there some other library I need to include for using Numpy arrays in C, or should I be looking elsewhere? The gcc command I've been using is included below.
gcc -Wall -shared Pipeline.cpp -I"C:/Python38/include" -I"C:/Program Files/Pleora Technologies Inc/eBUS SDK/Includes" -I "C:/Python38/Lib/site-packages/numpy/core/include" -L"C:/Python38/libs" -L"C:/Program Files/Pleora Technologies Inc/eBUS SDK/Libraries" -o lib.dll -lPvBuffer64 -lPvDevice64 -lPvStream64 -lPvAppUtils64 -lPvSystem64 -lSimpleImagingLib64 -lPvGenICam64 -lPvSerial64 -lPvBase64 -lPtUtilsLib64
I would avoid using the C Python interface to numpy and use a library link xtensor (found here).
I'm starting the study of Python/C API and I make the first code to test some functions, I write this:
file: test.c
#include "Python.h"
int main() {
PyObject* none = Py_BuildValue("");
}
I compile with command:
gcc -I/usr/include/python2.7 test.c
I've the error undefined reference to `Py_BuildValue'
After I run:
gcc -I/usr/include/python2.7 --shared -fPIC hashmem.c
this compile without errors, but when I run the compiled file I've a
Segmentation fault (core dumped)
How do I set the gcc parameters?
I've ubuntu 12.04, python 2.7.3, gcc 4.6.3 and I installed python-dev.
Thanks.
In the comments #Pablo has provided the solution
gcc -I/usr/include/python2.7 test.c -lpython2.7
I forgot to link the python library with the "-l" parameter.
-llibrary
-l library
Search the library named library when linking. (The second alternative with the library as a separate argument is only for POSIX) compliance and is not recommended.)It makes a difference where in the command you write this option; the linker searches and processes libraries and object files in the order they are specified. Thus, foo.o -lz bar.o' searches libraryz' after file foo.o but before bar.o. If bar.o refers to functions in z', those functions may not be loaded.The linker searches a standard list of directories for the library, which is actually a file named liblibrary.a. The linker then uses this file as if it had been specified precisely by name.The directories searched include several standard system directories plus any that you specify with -L.Normally the files found this way are library files—archive files whose members are object files. The linker handles an archive file by scanning through it for members which define symbols that have so far been referenced but not defined. But if the file that is found is an ordinary object file, it is linked in the usual fashion. The only difference between using an -l option and specifying a file name is that - l surrounds library withlib' and `.a' and searches several directories.
Parameter description source
So I have a few Python C extensions I have previously built for and used in 32 bit Python running in Win7. I have now however switched to 64 bit Python, and I am having issues building the C extension with MinGW-w64.
I made the changes to distutils as per this post, but I am getting some weird errors suggesting something is wrong:
$ python setup.py build
running build
running build_ext
building 'MyLib' extension
c:\MinGW64\bin\x86_64-w64-mingw32-gcc.exe -mdll -O -Wall -Ic:\Python27\lib\site-packages\numpy\core\include -Ic:\Python27\include -Ic:\Python27\PC -c MyLib.c -o build\temp.win-amd64-2.7\Release\mylib.o
MyLib.c: In function 'initMyLib':
MyLib.c:631:5: warning: implicit declaration of function 'Py_InitModule4_64' [-Wimplicit-function-declaration]
writing build\temp.win-amd64-2.7\Release\MyLib.def
c:\MinGW64\bin\x86_64-w64-mingw32-gcc.exe -shared -s build\temp.win-amd64-2.7\Release\mylib.o build\temp.win-amd64-2.7\Release\MyLib.def -Lc:\Python27\libs -Lc:\Python27\PCbuild\amd64 -lpython27 -o build\lib.win-amd64-2.7\MyLib.pyd
build\temp.win-amd64-2.7\Release\mylib.o:MyLib.c:(.text+0x13d): undefined reference to `__imp_PyExc_ValueError'
build\temp.win-amd64-2.7\Release\mylib.o:MyLib.c:(.text+0x1275): undefined reference to `__imp_PyExc_ValueError'
build\temp.win-amd64-2.7\Release\mylib.o:MyLib.c:(.text+0x1eef): undefined reference to `__imp_PyExc_ImportError'
build\temp.win-amd64-2.7\Release\mylib.o:MyLib.c:(.text+0x1f38): undefined reference to `__imp_PyExc_AttributeError'
build\temp.win-amd64-2.7\Release\mylib.o:MyLib.c:(.text+0x1f4d): undefined reference to `__imp_PyCObject_Type'
build\temp.win-amd64-2.7\Release\mylib.o:MyLib.c:(.text+0x1f61): undefined reference to `__imp_PyExc_RuntimeError'
build\temp.win-amd64-2.7\Release\mylib.o:MyLib.c:(.text+0x1fc7): undefined reference to `__imp_PyExc_RuntimeError'
build\temp.win-amd64-2.7\Release\mylib.o:MyLib.c:(.text+0x1ffe): undefined reference to `__imp_PyExc_RuntimeError'
build\temp.win-amd64-2.7\Release\mylib.o:MyLib.c:(.text+0x2042): undefined reference to `__imp_PyExc_RuntimeError'
build\temp.win-amd64-2.7\Release\mylib.o:MyLib.c:(.text+0x206c): undefined reference to `__imp_PyExc_RuntimeError'
build\temp.win-amd64-2.7\Release\mylib.o:MyLib.c:(.text+0x208a): more undefined references to `__imp_PyExc_RuntimeError' follow
build\temp.win-amd64-2.7\Release\mylib.o:MyLib.c:(.text+0x20a7): undefined reference to `__imp_PyExc_ImportError'
collect2.exe: error: ld returned 1 exit status
error: command 'x86_64-w64-mingw32-gcc' failed with exit status 1
I have googled around quite a bit to find information, but it's not easy to find a definite answer. Could someone shed some light on this? What further changes should I do to be able to successfully build C extensions for 64 bit Python in Win7?
EDIT:
After some helpful pointers in cgohlke's comments below I managed to generate libpython27.a. However after following the advice on this post (2nd to last) I still had a the __imp_Py_InitModule4_64 error. After some serious Google-fu I managed to trip over this post telling me to rename the Py_InitModule4 line to Py_InitModule4_64. After that everything worked swimmingly.
This worked for me with Python 3.3 :
create static python lib from dll
python dll is usually in C:/Windows/System32; in msys shell:
gendef.exe python33.dll
dlltool.exe --dllname python33.dll --def python33.def --output-lib libpython33.a
mv libpython33.a C:/Python33/libs
use swig to generate wrappers
e.g., swig -c++ -python myExtension.i
wrapper MUST be compiled with MS_WIN64, or your computer will crash when you import the class in Python
g++ -c myExtension.cpp -I/other/includes
g++ -DMS_WIN64 -c myExtension_wrap.cxx -IC:/Python33/include
shared library
g++ -shared -o _myExtension.pyd myExtension.o myExtension_wrap.o -lPython33 -lOtherSharedLibs -LC:/Python33/libs -LC:/path/to/other/shared/libs
make sure all shared libs (gdal, OtherSharedLibs) are in your PATH
(windows does not use LD_LIBRARY_PATH or PYTHONPATH)
in Python, just: import myExtension
voila!
I realize this is an old question, but it is still the top search result. Today, in 2019, I was able to do this:
https://github.com/PetterS/quickjs/commit/67bc2428b8c0716538b4583f4f2b0a2a5a49106c
In short:
Make sure a 64-bit version of mingw-w64 is in the PATH.
Monkey-patch distutils:
import distutils.cygwinccompiler
distutils.cygwinccompiler.get_msvcr = lambda: []
Some differences in the shell w.r.t. escaping.
extra_link_args = ["-Wl,-Bstatic", "-lpthread"] in order to link statically and not have extra runtime deps.
pipenv run python setup.py build -c mingw32 now works.
Here is a example code for VC++ Build Tools
https://github.com/starnight/python-c-extension/tree/master/00-HelloWorld
You could try:
python setup.py -c mingw32
However this is not work for me.
My Solution is:
install Anaconda 64bit python 3.6
install mingw64
add mingw64/bin to PATH
compile dll from c file by
gcc -c libmypy.c -IC:\Users\{user_name}\Anaconda3\pkgs\python-3.6.4-h6538335_1\include
gcc -shared -o libmypy.dll libmypy.o -LC:\Users\{user_name}\Anaconda3\pkgs\python-3.6.4-h6538335_1\libs -lPython36
load dll file in .py script
from ctypes import *
m = cdll.LoadLibrary(r"C:\{path_to_dll}\libmypy.dll")
print(m.hello())
I created a monkey-patch for setuptools to let you to build_ext with mingw64 on Windows easily. See https://github.com/imba-tjd/mingw64ccompiler
I used this thread to wade through learning how to make a C extension, and since most of what I learned is in it, I thought I'd put the final discovery here too, so that someone else can find it if they are looking.
I wasn't trying to compile something big, just the example in Hetland's Beginning Python. Here is what I did (the example C pgm is called palindrome.c). I'm using Anaconda with python 3.7 in it, and the TDM-GCC version of MinGW64. I put all of the tools used into my Path, and all of the paths needed in PYTHONPATH, and the ..\Anaconda3 directory into PYTHON_HOME. I still ended up using explicit paths on some things.
I created the libpython37.a library with gendef.exe and dlltool.exe as Mark said above, and put it in ..\Anaconda3\libs.
I followed the prescription in Hetland:
gcc -c palindrome.c
gcc -I$PYTHON_HOME -I$PYTHON_HOME/Include -c palindrome_wrap.c
The second failed, the compiler couldn't find Python.h, the following worked:
gcc -I[somedirectories]\Anaconda3\Include -c palindrome_wrap.c
I then did, as many have said, including Hetland 3rd ed.,
gcc -shared palindrome.o palindrome_wrap.o [somedirectories]/Anaconda3/libs/libpython37.a -o _palindrome.dll
This did not work. Even with the Load Library cswu used (which I found elsewhere, too).
So I gendef'd _palindrome.dll and couldn't find the function in it, "is_palindrome" in the exports. I went through some of the SWIG documentation, and declared the function both in the %{ %} section and below it, both extern, that finally got the function extern'd in palindrome_wrap.c as it should have been. But no export, so I went back into palindrome.c and redeclared the function as:
declspec(dllexport) extern int __stdcall is_palindrome(char* text)
and redeclared it in palindrome.i in both places as above with this signature.
Partial success! It got listed in the Export section when I gendef'd _palindrome.dll and I could do cswu's call using Load Library. But still not do what Hetland says and do
import _palindrome
in Python.
Going back to all the sources again, I could not figure this out. I finally started reading the SWIG documentation from the beginning leaving no stone unturned -- Searching through the manual doesn't produce the place found.
At the end of Introduction Sec. 2.7 Incorporating Into a Build System, under the sample Make process, it says:
"The above example will generate native build files such as makefiles, nmake files and Visual Studio projects which will invoke SWIG and compile the generated C++ files into _example.so (UNIX) or _example.pyd (Windows). For other target languages on Windows a dll, instead of a .pyd file, is usually generated."
And that's the answer to the last problem:
The compile step for the dll should read:
gcc -shared palindrome.o palindrome_wrap.o [somedirectories]/Anaconda3/libs/libpython37.a -o _palindrome.pyd
(I didn't go back and change out my declspec declarations so I don't know whether they were necessary, so they were still there too).
I got a file, _palindrome.pyd
Which if in the PYTHONPATH (mine was local) works, and one can then do
import _palindrome
from _palindrome import is_palindrome
and use the exported, properly wrapped and packaged C function, compiled with TDM-GCC, in python as promised. gcc, which is MinGW64 in a different installation, knows how to do the .pyd file. I diffed the dll and pyd since they were the same byte length. They are not the same at hundreds of points.
Hope this helps someone else.