1
1

More than 3 years have passed since last update.

PHPエクステンションをCMakeする

Last updated at Posted at 2020-03-16

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のサンプルがあったので調整してみました。
動作確認の引数をいつも忘れるので備忘録です。:relaxed:

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1