I have a C++ library I would like to link to and use in PHP: libsigx.a
I would like to link with it by putting it in my config.m4 file (Zend).
[config.m4]
PHP_ARG_ENABLE(sigx,
[Whether to enable the "sigx" extension],
[ --enable-sigx Enable "sigx" extension support])
if test $PHP_SIGX != "no"; then
PHP_REQUIRE_CXX()
PHP_SUBST(SIGX_SHARED_LIBADD)
PHP_ADD_LIBRARY(stdc++, 1, SIGX_SHARED_LIBADD)
PHP_ADD_LIBRARY(stdc++, 1, "libsigx.a")
PHP_NEW_EXTENSION(sigx, sigx.cc, $ext_shared)
fi
This is not working for me. I can run phpize and ./configure just fine, but when I go to run a test script, it complains about objects in the library not being available.
What I said in my comment worked.
PHP_ADD_LIBRARY_WITH_PATH(sigx, ., SIGX_SHARED_LIBADD)
Related
I'm writing an extension for PHP, I didn't have many problems creating the module, compiling, enabling it in Apache and putting the standard example to work.
I modified the default project (added a class with method and property, added information to be displayed in phpinfo, configured to accept c ++, configured the IDE CLion to build the project using commands in CMake) and still had no problems.
My difficulty started when I tried to really use my code, I created a static library (I did the unit tests with cunit, I went through valgrind without any problem) and I tried to use the extension and it doesn't work, I believe the problem is in the configuration of " config.m4 "
If I try to use PHP_CHECK_LIBRARY I get the error message:
./configure: line 4787: unset: `ac_cv_lib_nerd4ever-kaya-wrapper_fn_kaya_login': not a valid identifier
configure: error: wrong nerd4eve-kaya lib not found
If I directly included the library the project compiles, but has error when trying to load:
PHP_ADD_LIBRARY(nerd4ever-kaya-wrapper, 1, KAYA_SHARED_LIBADD)
Error in apache when try include library directly
PHP Warning: PHP Startup: Unable to load dynamic library 'kaya' (tried: /usr/lib/php/20180731/kaya (/usr/lib/php/20180731/kaya: cannot open shared object file: No such file or directory), /usr/lib/php/20180731/kaya.so (/usr/lib/php/20180731/kaya.so: undefined symbol: _ZN9nerd4ever4kaya9ExceptionD1Ev)) in Unknown on line 0
I try check the symbols in my library using the command "nm -C libnerd4ever-kaya-wrapper.a | less" and the fn_kaya_login is displayed
kaya_client.cc.o:
...
00000000 T fn_kaya_login
...
My config.m4
PHP_ARG_ENABLE(kaya, whether to enable kaya support,
[ --enable-kaya Enable kaya support], no)
if test "$PHP_KAYA" != "no"; then
PHP_ADD_INCLUDE(/usr/include)
PHP_REQUIRE_CXX()
PHP_ADD_LIBRARY(stdc++, 1, KAYA_SHARED_LIBADD)
PHP_ADD_LIBRARY(jsoncpp, 1, KAYA_SHARED_LIBADD)
PHP_ADD_LIBRARY(curl, 1, KAYA_SHARED_LIBADD)
KAYA_BASE_DIR="$KAYA_DIR./../.."
AC_MSG_CHECKING(for kaya base dir)
if [ test -d "$KAYA_BASE_DIR" ]; then
dnl nerd4ever-kaya.a
KAYA_LIBRARY_PATH=`find $KAYA_BASE_DIR -type f -name "*nerd4ever-kaya-wrapper.a" | head -1 | xargs readlink -f | xargs dirname`
if [ test -z "$KAYA_LIBRARY_PATH" ]; then
AC_MSG_RESULT(["libs: not found"])
AC_MSG_ERROR(["static lib kaya is required"])
else
AC_MSG_RESULT(["libs kaya: ${KAYA_LIBRARY_PATH}"])
PHP_ADD_INCLUDE($KAYA_BASE_DIR/sources)
PHP_ADD_LIBPATH($KAYA_LIBRARY_PATH)
dnl PHP_ADD_LIBRARY(nerd4ever-kaya-wrapper, 1, KAYA_SHARED_LIBADD)
dnl PHP_CHECK_LIBRARY(nerd4ever-kaya-wrapper, fn_kaya_login,
dnl [
dnl PHP_ADD_LIBRARY(nerd4ever-kaya-wrapper, 1, KAYA_SHARED_LIBADD)
dnl AC_DEFINE(HAVE_KAYA, 1, [ Have kaya support ])
dnl ],[
dnl AC_MSG_ERROR([wrong nerd4eve-kaya lib not found])
dnl ],[
dnl -L$KAYA_LIBRARY_PATH -lnerd4ever-kaya-wrapper
dnl ])
dnl dnl PHP_ADD_LIBRARY_WITH_PATH(nerd4ever-kaya, KAYA_LIBRARY_PATH, EXTRA_LDFLAGS)
fi
fi
PHP_SUBST(KAYA_SHARED_LIBADD)
PHP_NEW_EXTENSION(kaya, php_kaya.cpp, $ext_shared,,)
fi
I have difficulty trying to write a php extension that uses an external shared library:
The content of config.m4 is as follows:
PHP_ARG_WITH([foo],
[for foo support],
[AS_HELP_STRING([--with-foo],
[Include foo support])])
if test "$PHP_FOO" != "no"; then
PKG_CHECK_MODULES([LIBFREETYPE2], [freetype2 >= 23.4.17])
PHP_EVAL_INCLINE($LIBFREETYPE2_CFLAGS)
PHP_EVAL_LIBLINE($LIBFREETYPE2_LIBS, FOO_SHARED_LIBADD)
PHP_NEW_EXTENSION(foo, foo.c, $ext_shared)
fi
The code of the main function in foo.c is as follows(Just a very simple example of using the external FreeType library):
PHP_FUNCTION(foo_test) {
ZEND_PARSE_PARAMETERS_NONE();
FT_Library ft;
if (FT_Init_FreeType(&ft)) {
php_printf("FreeType library failed to load\n");
return;
}
php_printf("FreeType library successfully loaded\n");
FT_Done_Library(ft);
php_printf("FreeType library unloaded\n");
}
phpize, ./configure, make and make install all succeeded, and then I added the extension in php.ini:
extension = foo.so
So far so good, but then I ran the following command
echo "<?php foo_test();" | php
I got the following error message:
php: symbol lookup error: /the-path-of-foo/foo.so: undefined symbol:
FT_Init_FreeType
It looks like PHP doesn't load the external shared FreeType library my PHP extension intends to use.
How do I do to make PHP load the external shared FreeType library?
Thanks for help.
Resolved this issue by adding PHP_SUBST(FOO_SHARED_LIBADD) after PHP_EVAL_LIBLINE($LIBFREETYPE2_LIBS, FOO_SHARED_LIBADD):
PHP_ARG_WITH([foo],
[for foo support],
[AS_HELP_STRING([--with-foo],
[Include foo support])])
if test "$PHP_FOO" != "no"; then
PKG_CHECK_MODULES([LIBFREETYPE2], [freetype2 >= 23.4.17])
PHP_EVAL_INCLINE($LIBFREETYPE2_CFLAGS)
PHP_EVAL_LIBLINE($LIBFREETYPE2_LIBS, FOO_SHARED_LIBADD)
PHP_SUBST(FOO_SHARED_LIBADD)
PHP_NEW_EXTENSION(foo, foo.c, $ext_shared)
fi
Your config.m4 shoud be like
...
PHP_EVAL_LIBLINE($LIBFREETYPE2_LIBS, EXTRA_CFLAGS)
PHP_SUBST(EXTRA_CFLAGS)
PHP_NEW_EXTENSION(foo, foo.c, $ext_shared)
fi
Problem
I am learning to create a php extension. I have created a php extension for a basic hello world app. But the moment I try to include functions from the C library I am trying to entend then I get the following error message:
PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib/php5/20121212/hello.so' - /usr/lib/php5/20121212/hello.so: undefined symbol: nc_open in Unknown on line 0
This nc_open() function is the key function in the libary I am trying to extend
Process
I have created by header and config files and my c extension file which contains:
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_hello.h"
#include <netcdf.h>
...
PHP_FUNCTION(hello_world)
{
int status;
int ncid;
status = nc_open("sample.nc", 0, &ncid);
RETURN_LONG(status);
}
I have set up a directory (on Ubuntu) and run the phpize and configure steps. I run the make command which runs with no errors.
In my php.ini file I have the hello.so extension which points to symbolic link to the file I make.
I then restart the apache server on my local machine and then run:
php -r 'echo hello_world();'
and get:
- /usr/lib/php5/20121212/hello.so: undefined symbol: nc_open in Unknown on line 0
PHP Warning: Module 'xdebug' already loaded in Unknown on line 0
PHP Fatal error: Call to undefined function hello_world() in Command line code on line 1
PHP Stack trace:
PHP 1. {main}() Command line code:0
The error only occurs when I have a function from netcdf.h
The error does not occur from just having the include statement.
What I've tried:
Firstly I tried writing a basic c program to check that it would work, I managed to succeed by compiling it with:
gcc test.c -lnetcdf -o Test
and running ./Test
I tried using the following MakeFile
LDLIBS = -lnetcdf
but was unsuccessful.
What I would like:
Preferably to know how to get this library to work in my extension but I would settle for being pointed to documents or examples to help me understand what I need to know to accomplish this.
Update
Following Elliott Frisch's comments I have tried the
Setting the PHP_RPATHS=/usr/local
Setting /etc/ld.so.conf to:
include /etc/ld.so.conf.d/*.conf
/usr/lib
Changing the MakeFile to:
LDLIBS = -lnetcdf
LDFLAGS = -static
I am making the assumption that /usr/local is the correct directory due to it containing netcdf.so
I have added the following lines to my config.m4 file according to try adding the suggested functions
PHP_ADD_INCLUDE(/usr/lib)
PHP_ADD_LIBRARY_WITH_PATH(netcdf, /usr/lib, HELLO_SHARED_LIBADD)
Unfortunately I am still getting the problem so I am trying to understand what these functions mean to make sure I using them correctly. (The library I need to connect to is /usr/lib/libnetcdf.a and need to include netcdf.h from that file.)
You'll need to use PHP_ADD_LIBRARY_WITH_PATH & PHP_ADD_INCLUDE macros in config.m4 to handle linking. Autoconf's macros are also helpful for find & verifying existing libraries.
The best examples can be found in the ext directory of PHP's source code. Like ext/zlib
PHP_ADD_LIBPATH($ZLIB_DIR/$PHP_LIBDIR, ZLIB_SHARED_LIBADD)
PHP_ZLIB_DIR=$ZLIB_DIR
PHP_ADD_LIBRARY(z,, ZLIB_SHARED_LIBADD)
PHP_ADD_INCLUDE($ZLIB_INCDIR)
And more detailed examples in ext/oracle (from apple's open source labs)
PHP_ADD_LIBRARY(clntsh, 1, ORACLE_SHARED_LIBADD)
PHP_ADD_LIBPATH($ORACLE_DIR/lib, ORACLE_SHARED_LIBADD)
The issue was with an incorrectly configured config.m4 file.
I added the following that I modified from examples I found to get it to work:
if test "$PHP_HELLO" != "no"; then
SEARCH_PATH="/usr/local /usr" # you might want to change this
SEARCH_FOR="/include/netcdf.h" # you most likely want to change this
if test -r $PHP_HELLO/$SEARCH_FOR; then # path given as parameter
HELLO_INC_DIR=$PHP_HELLO/include
else # search default path list
AC_MSG_CHECKING([for netcdf.h in default path])
for i in $SEARCH_PATH ; do
if test -r $i/$SEARCH_FOR; then
HELLO_INC_DIR=$i/include
AC_MSG_RESULT(found in $i)
fi
done
fi
if test -z "$HELLO_INC_DIR"; then
AC_MSG_RESULT([not found])
fi
SEARCH_PATH="/usr/local /usr" # you might want to change this
SEARCH_FOR="/lib/libnetcdf.a" # you most likely want to change this
if test -r $PHP_HELLO/$SEARCH_FOR; then # path given as parameter
HELLO_LIB_DIR=$PHP_HELLO/lib
else # search default path list
AC_MSG_CHECKING([for libnetcdf in default path])
for i in $SEARCH_PATH ; do
if test -r $i/$SEARCH_FOR; then
HELLO_LIB_DIR=$i/lib
AC_MSG_RESULT(found in $i)
fi
done
fi
if test -z "$HELLO_LIB_DIR"; then
AC_MSG_RESULT([not found])
AC_MSG_ERROR([Please check the netCDF distribution])
fi
# --with-netcdf -> add include path
PHP_ADD_INCLUDE($HELLO_INC_DIR)
# --with-netcdf -> check for lib and symbol presence
LIBNAME=netcdf # you may want to change this
dnl O_LDFLAGS=$LDFLAGS
dnl LDFLAGS="$LDFLAGS -L$NETCDF_LIB_DIR -l$LIBNAME"
PHP_ADD_LIBRARY($LIBNAME)
LIBSYMBOL=nc_inq_libvers # you most likely want to change this
PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,
[
PHP_ADD_LIBRARY($LIBNAME)
AC_DEFINE(HAVE_HELLO,1,[Build netCDF extension])
],[
AC_MSG_ERROR([wrong netCDF library version or lib not found])
])
PHP_SUBST(HELLO_SHARED_LIBADD)
HELLO_SHARED_LIBADD=-l$LIBNAME
I want to write a test php extension, which will provide a test class. I want to extract class declaration into a separate C-File and call class registration from module init function of myext.c file. I have the following files:
testlib/
test_class.c
myext.c
php_myext.h
config.m4
...
Now config.m4 file is quite simple:
PHP_ARG_ENABLE(myext, [whether to enable myext support], [ --enable-myext Enable myext support])
if test "$PHP_MYEXT" != "no"; then
PHP_NEW_EXTENSION(myext, myext.c, $ext_shared)
fi
How to configure config.m4 to be able to add test_class.c to extension building?
UPDATE:
How to configure config.m4 to make it searching .c files in a specific folder and add to extension building automatically?
It's pretty straightforward:
PHP_NEW_EXTENSION(myext, myext.c testlib/test_class.c, $ext_shared)
I wrote an extension in C++ that uses libtidy, and it runs perfectly under PHP when I compile PHP --with-tidy.
However, it would be nice to have the extension run on a vanilla PHP. When I try to use the extension, I get something like:
PHP Warning:
PHP Startup:
Unable to load dynamic library 'extension.so':
undefined symbol: tidyCleanAndRepair in Unknown on line 0
and the extension is not loaded.
Obviously, the official tidy extension works fine. I have the relevant libtidy development packages installed on the system, and it compiles+links without a problem. I have tried to look through the code for the tidy extension, but it is a huge mass of macros - copying pieces at random felt like cargo code.
Besides linking to the library with PHP_ADD_LIBRARY_WITH_PATH(tidy, $TIDY_LIBDIR, TIDY_SHARED_LIBADD), Is there a PHP extension or C statement that fixes this error?
Thanks in advance!!
EDIT: here is the entire config.m4 file:
dnl config.m4 for extension htmlparser
PHP_ARG_ENABLE(htmlparse, whether to enable htmlparser support,
[ --enable-htmlparser Enable htmlparser support])
if test "$PHP_HTMLPARSER" != "no"; then
if test -r $PHP_LIBXML2/lib/libxml2.a; then
LIBXML2_DIR=$PHP_LIBXML2
else
AC_MSG_CHECKING(for libxml2 in default path)
for i in /usr/local /usr; do
if test -r $i/lib/libxml2.a; then
LIBXML2_DIR=$i
AC_MSG_RESULT(found in $i)
fi
done
fi
if test -z "$LIBXML2_DIR"; then
AC_MSG_RESULT(not found)
AC_MSG_ERROR(Please reinstall the libxml2 distribution - libxml2.h should
be in <libxml2-dir>/include and libxml2.a should be in <libxml2- dir>/lib)
fi
PHP_ADD_INCLUDE($LIBXML2_DIR/include/libxml2)
PHP_ADD_LIBRARY_WITH_PATH(libxml2, $LIBXML2_DIR/lib, LIBXML2_SHARED_LIBADD)
AC_MSG_CHECKING(for boost in default path)
for i in /usr/local /usr; do
if test -r $i/include/boost; then
BOOST_DIR=$i
AC_MSG_RESULT(found in $i)
fi
done
if test -z "$BOOST_DIR"; then
AC_MSG_RESULT(not found)
AC_MSG_ERROR(Please reinstall the boost distribution!!!)
fi
PHP_ADD_INCLUDE($BOOST_DIR/include/boost/)
TIDY_SEARCH_DIRS="/usr/local /usr"
for i in $TIDY_SEARCH_DIRS; do
if test -f $i/include/tidy/tidy.h; then
TIDY_DIR=$i
TIDY_INCDIR=$i/include/tidy
elif test -f $i/include/tidy.h; then
TIDY_DIR=$i
TIDY_INCDIR=$i/include
fi
done
if test -z "$TIDY_DIR"; then
AC_MSG_ERROR(Cannot find libtidy)
fi
TIDY_LIBDIR=$TIDY_DIR/lib
PHP_ADD_INCLUDE($TIDY_INCDIR)
PHP_ADD_LIBRARY_WITH_PATH(tidy, $TIDY_LIBDIR, TIDY_SHARED_LIBADD)
PHP_CHECK_LIBRARY(tidy,tidyOptGetDoc,
[
AC_DEFINE(HAVE_TIDYOPTGETDOC,1,[ ])
],[],[])
AC_DEFINE(HAVE_HTMLPARSER, 1, [Whether you want htmlparser support])
PHP_SUBST(HTMLPARSER_SHARED_LIBADD)
PHP_ADD_LIBRARY_WITH_PATH(stdc++, 1, HTMLPARSER_SHARED_LIBADD)
PHP_REQUIRE_CXX()
PHP_NEW_EXTENSION(htmlparser, php_htmlparser.cpp parsehtml.cpp StringBuilder.cpp, $ext_shared)
fi
did you compile your extension with the same php version as a vanilla php? you should use php sources with the same version.
besides, make sure that in php.ini file you loaded 'libtidy' extension before your extension.