PHP extensionをCMakeを使ってビルドする
構成
sample/
CMakeLists.txt
config.cmake
config.h.in
php_sample.h
sample.c
test.php
各ファイル
CMakeLists.txt
cmake_minimum_required(VERSION 3.5.1)
project(sample-ext)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_FLAGS "-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DPHP_ATOM_INC -DHAVE_CONFIG_H -O3 -funroll-loops")
execute_process(COMMAND "php-config" "--prefix" OUTPUT_VARIABLE PHP_BASE_PATH OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND "php-config" "--include-dir" OUTPUT_VARIABLE PHP_INCLUDE_PATH OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND "php-config" "--extension-dir" OUTPUT_VARIABLE EXTENSION_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
set(COMPILE_DL_SAMPLE 1)
set(HAVE_SAMPLE 1)
include(config.cmake)
include_directories(
"${PHP_INCLUDE_PATH}"
"${PHP_INCLUDE_PATH}/main"
"${PHP_INCLUDE_PATH}/TSRM"
"${PHP_INCLUDE_PATH}/Zend"
"${PHP_INCLUDE_PATH}/ext"
"${PHP_INCLUDE_PATH}/ext/date/lib"
${CMAKE_BINARY_DIR})
add_library(sample-shared SHARED
${CMAKE_CURRENT_SOURCE_DIR}/sample.c)
set_target_properties(sample-shared PROPERTIES LINK_FLAGS "-Wl,-rpath,${PHP_BASE_PATH}/lib")
set_target_properties(sample-shared PROPERTIES PREFIX "" OUTPUT_NAME sample)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/sample.so
DESTINATION ${EXTENSION_DIR}
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE
GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
config.cmake
find_path(DLFCN_H_PATH dlfcn.h PATHS /usr /usr/local PATH_SUFFIXES include)
find_path(INTTYPES_H_PATH inttypes.h PATHS /usr /usr/local PATH_SUFFIXES include)
find_path(MEMORY_H_PATH memory.h PATHS /usr /usr/local PATH_SUFFIXES include)
find_path(STDINT_H_PATH stdint.h PATHS /usr /usr/local PATH_SUFFIXES include)
find_path(STDLIB_H_PATH stdlib.h PATHS /usr /usr/local PATH_SUFFIXES include)
find_path(STRINGS_H_PATH strings.h PATHS /usr /usr/local PATH_SUFFIXES include)
find_path(STRING_H_PATH string.h PATHS /usr /usr/local PATH_SUFFIXES include)
find_path(SYS_STAT_H_PATH sys/stat.h PATHS /usr /usr/local PATH_SUFFIXES include)
find_path(SYS_TYPES_H_PATH sys/types.h PATHS /usr /usr/local PATH_SUFFIXES include)
find_path(UNISTD_H_PATH unistd.h PATHS /usr /usr/local PATH_SUFFIXES include)
if (DLFCN_H_PATH)
set(HAVE_DLFCN_H 1)
endif (DLFCN_H_PATH)
if (INTTYPES_H_PATH)
set(HAVE_INTTYPES_H 1)
endif (INTTYPES_H_PATH)
if (MEMORY_H_PATH)
set(HAVE_MEMORY_H 1)
endif (MEMORY_H_PATH)
if (STDINT_H_PATH)
set(HAVE_STDINT_H 1)
endif (STDINT_H_PATH)
if (STDLIB_H_PATH)
set(HAVE_STDLIB_H 1)
endif (STDLIB_H_PATH)
if (STRINGS_H_PATH)
set(HAVE_STRINGS_H 1)
endif (STRINGS_H_PATH)
if (STRING_H_PATH)
set(HAVE_STRING_H 1)
endif (STRING_H_PATH)
if (SYS_STAT_H_PATH)
set(HAVE_SYS_STAT_H 1)
endif (SYS_STAT_H_PATH)
if (SYS_TYPES_H_PATH)
set(HAVE_SYS_TYPES_H 1)
endif (SYS_TYPES_H_PATH)
if (UNISTD_H_PATH)
set(HAVE_UNISTD_H 1)
endif (UNISTD_H_PATH)
set(PACKAGE_BUGREPORT "")
set(PACKAGE_NAME "")
set(PACKAGE_STRING "")
set(PACKAGE_TARNAME "")
set(PACKAGE_URL "")
set(PACKAGE_VERSION "")
if (DLFCN_H_PATH AND
INTTYPES_H_PATH AND
MEMORY_H_PATH AND
STDINT_H_PATH AND
STDLIB_H_PATH AND
STRINGS_H_PATH AND
STRING_H_PATH AND
SYS_STAT_H_PATH AND
SYS_TYPES_H_PATH AND
UNISTD_H_PATH)
set(STDC_HEADERS 1)
endif (DLFCN_H_PATH AND
INTTYPES_H_PATH AND
MEMORY_H_PATH AND
STDINT_H_PATH AND
STDLIB_H_PATH AND
STRINGS_H_PATH AND
STRING_H_PATH AND
SYS_STAT_H_PATH AND
SYS_TYPES_H_PATH AND
UNISTD_H_PATH)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/config.h.in
${CMAKE_BINARY_DIR}/config.h)
config.h.in
# cmakedefine COMPILE_DL_SAMPLE @COMPILE_DL_SAMPLE@
# cmakedefine HAVE_DLFCN_H @HAVE_DLFCN_H@
# cmakedefine HAVE_INTTYPES_H @HAVE_INTTYPES_H@
# cmakedefine HAVE_MEMORY_H @HAVE_MEMORY_H@
# cmakedefine HAVE_SAMPLE @HAVE_SAMPLE@
# cmakedefine HAVE_STDINT_H @HAVE_STDINT_H@
# cmakedefine HAVE_STDLIB_H @HAVE_STDLIB_H@
# cmakedefine HAVE_STRINGS_H @HAVE_STRINGS_H@
# cmakedefine HAVE_STRING_H @HAVE_STRING_H@
# cmakedefine HAVE_SYS_STAT_H @HAVE_SYS_STAT_H@
# cmakedefine HAVE_SYS_TYPES_H @HAVE_SYS_TYPES_H@
# cmakedefine HAVE_UNISTD_H @HAVE_UNISTD_H@
# cmakedefine NO_MINUS_C_MINUS_O @NO_MINUS_C_MINUS_O@
# define PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@"
# define PACKAGE_NAME "@PACKAGE_NAME@"
# define PACKAGE_STRING "@PACKAGE_STRING@"
# define PACKAGE_TARNAME "@PACKAGE_TARNAME@"
# define PACKAGE_URL "@PACKAGE_URL@"
# define PACKAGE_VERSION "@PACKAGE_VERSION@"
# cmakedefine STDC_HEADERS @STDC_HEADERS@
上記はphpize
と./configure
が担当している部分ですが多分こんな感じです。
これがないとエラーになったので、config.h
はコピペした方が良いかもしれません。
php_sample.h
# ifndef PHP_SAMPLE_H
# define PHP_SAMPLE_H
extern zend_module_entry sample_module_entry;
# define phpext_sample_ptr &sample_module_entry
# define PHP_SAMPLE_VERSION "0.1.0"
# if defined(ZTS) && defined(COMPILE_DL_SAMPLE)
ZEND_TSRMLS_CACHE_EXTERN()
# endif
# endif /* PHP_SAMPLE_H */
sample.c
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
# include "php.h"
# include "ext/standard/info.h"
# include "php_sample.h"
/* For compatibility with older PHP versions */
# ifndef ZEND_PARSE_PARAMETERS_NONE
# define ZEND_PARSE_PARAMETERS_NONE() \
ZEND_PARSE_PARAMETERS_START(0, 0) \
ZEND_PARSE_PARAMETERS_END()
# endif
/* {{{ void sample_test1()
*/
PHP_FUNCTION(sample_test1)
{
ZEND_PARSE_PARAMETERS_NONE();
php_printf("The extension %s is loaded and working!\r\n", "sample");
}
/* }}} */
/* {{{ string sample_test2( [ string $var ] )
*/
PHP_FUNCTION(sample_test2)
{
char *var = "World";
size_t var_len = sizeof("World") - 1;
zend_string *retval;
ZEND_PARSE_PARAMETERS_START(0, 1)
Z_PARAM_OPTIONAL
Z_PARAM_STRING(var, var_len)
ZEND_PARSE_PARAMETERS_END();
retval = strpprintf(0, "Hello %s", var);
RETURN_STR(retval);
}
/* }}}*/
/* {{{ PHP_RINIT_FUNCTION
*/
PHP_RINIT_FUNCTION(sample)
{
# if defined(ZTS) && defined(COMPILE_DL_SAMPLE)
ZEND_TSRMLS_CACHE_UPDATE();
# endif
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MINFO_FUNCTION
*/
PHP_MINFO_FUNCTION(sample)
{
php_info_print_table_start();
php_info_print_table_header(2, "sample support", "enabled");
php_info_print_table_end();
}
/* }}} */
/* {{{ arginfo
*/
ZEND_BEGIN_ARG_INFO(arginfo_sample_test1, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_sample_test2, 0)
ZEND_ARG_INFO(0, str)
ZEND_END_ARG_INFO()
/* }}} */
/* {{{ sample_functions[]
*/
static const zend_function_entry sample_functions[] = {
PHP_FE(sample_test1, arginfo_sample_test1)
PHP_FE(sample_test2, arginfo_sample_test2)
PHP_FE_END
};
/* }}} */
/* {{{ sample_module_entry
*/
zend_module_entry sample_module_entry = {
STANDARD_MODULE_HEADER,
"sample", /* Extension name */
sample_functions, /* zend_function_entry */
NULL, /* PHP_MINIT - Module initialization */
NULL, /* PHP_MSHUTDOWN - Module shutdown */
PHP_RINIT(sample), /* PHP_RINIT - Request initialization */
NULL, /* PHP_RSHUTDOWN - Request shutdown */
PHP_MINFO(sample), /* PHP_MINFO - Module info */
PHP_SAMPLE_VERSION, /* Version */
STANDARD_MODULE_PROPERTIES
};
/* }}} */
# ifdef COMPILE_DL_SAMPLE
# ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE()
# endif
ZEND_GET_MODULE(sample)
# endif
こちらはスケルトンそのままです。
test.php
<?php
sample_test1();
ビルド
$ mkdir build
$ cd build
$ cmake ..
$ make -j
動作確認
$ php -d extension=build/sample.so -f test.php
The extension sample is loaded and working!
phpize
sample.pb.cc
のようなファイル名だとIFS
コマンドで分割している箇所でおかしくなるのでCMakeのサンプルがあったので調整してみました。
動作確認の引数をいつも忘れるので備忘録です。