Organized modules, added indirection for FFI vs extension loading (#10)

* mv src -> ext, lib -> src to be more in line with PHP module expectations

* Fixed dependency for ffi test

* Fixed path in format-check to C source

* CRT will now try the extension first, then FFI
This commit is contained in:
Justin Boswell
2021-02-16 10:31:42 -08:00
committed by GitHub
parent aee57a929d
commit c30c1486fe
17 changed files with 141 additions and 46 deletions
+1
View File
@@ -181,6 +181,7 @@ fabric.properties
.libs/
build/
configure.in
configure.ac
mkinstalldirs
run-tests.php
Makefile.global
+11 -7
View File
@@ -40,16 +40,20 @@ $(BUILD_DIR)/aws-crt-ffi/CMakeCache.txt: $(INT_DIR)/lib/libcrypto.a
$(BUILD_DIR)/aws-crt-ffi/libaws-crt-ffi.so: $(BUILD_DIR)/aws-crt-ffi/CMakeCache.txt
$(CMAKE_BUILD) build/aws-crt-ffi $(CMAKE_TARGET)
# copy the lib into the lib folder
$(INSTALL_DIR)/lib/libaws-crt-ffi.so: $(BUILD_DIR)/aws-crt-ffi/libaws-crt-ffi.so $(INSTALL_DIR)/lib/api.h
cp -v $(BUILD_DIR)/aws-crt-ffi/libaws-crt-ffi.so $(INSTALL_DIR)/lib/libaws-crt-ffi.so
# copy the lib into the src folder
$(INSTALL_DIR)/src/libaws-crt-ffi.so: $(BUILD_DIR)/aws-crt-ffi/libaws-crt-ffi.so $(INSTALL_DIR)/src/api.h
cp -v $(BUILD_DIR)/aws-crt-ffi/libaws-crt-ffi.so $(INSTALL_DIR)/src/libaws-crt-ffi.so
# install api.h from FFI lib
$(INSTALL_DIR)/lib/api.h: crt/aws-crt-ffi/src/api.h
cat crt/aws-crt-ffi/src/api.h | grep -v AWS_EXTERN_C | sed -e 's/AWS_CRT_API //' | grep -ve '^#' > $(INSTALL_DIR)/lib/api.h
$(INSTALL_DIR)/src/api.h: crt/aws-crt-ffi/src/api.h
cat crt/aws-crt-ffi/src/api.h | grep -v AWS_EXTERN_C | sed -e 's/AWS_CRT_API //' | grep -ve '^#' > $(INSTALL_DIR)/src/api.h
# copy the FFI lib from src to ext for the extension to use
$(INSTALL_DIR)/ext/libaws-crt-ffi.so: $(INSTALL_DIR)/src/libaws-crt-ffi.so
cp -v $(INSTALL_DIR)/src/libaws-crt-ffi.so $(INSTALL_DIR)/ext/libaws-crt-ffi.so
# Force the crt object target to depend on the FFI library
src/crt.lo: $(INSTALL_DIR)/lib/libaws-crt-ffi.so
ext/crt.lo: $(INSTALL_DIR)/ext/libaws-crt-ffi.so
ifeq ($(TEST_FFI),1)
test-ci: test-ffi
@@ -58,6 +62,6 @@ test-ci: test
endif
# Test the FFI interface
test-ffi: $(INSTALL_DIR)/lib/libaws-crt-ffi.so
test-ffi: $(INSTALL_DIR)/src/libaws-crt-ffi.so
composer update
composer run test
+4 -7
View File
@@ -12,19 +12,16 @@
},
"autoload": {
"classmap": [
"lib/"
],
"psr-4": {
"AWS\\": "lib/AWS"
}
"src/"
]
},
"autoload-dev": {
"classmap": [
"lib/tests/"
"src/tests/"
]
},
"scripts": {
"test": "phpunit lib/tests"
"test": "phpunit src/tests"
},
"license": "Apache-2.0",
"authors": [
+1 -1
View File
@@ -17,7 +17,7 @@ if test "$PHP_AWSCRT" != "no"; then
PHP_SUBST(AWSCRT_SHARED_LIBADD)
# Sources for the PHP extension itself
AWSCRT_SOURCES=src/*.c
AWSCRT_SOURCES=ext/*.c
PHP_NEW_EXTENSION(awscrt, $AWSCRT_SOURCES, $ext_shared)
fi
+2
View File
@@ -0,0 +1,2 @@
*.so
api.h
View File
+1 -1
View File
@@ -10,7 +10,7 @@ if NOT type $CLANG_FORMAT 2> /dev/null ; then
fi
FAIL=0
SOURCE_FILES=`find src -type f \( -name '*.h' -o -name '*.c' \)`
SOURCE_FILES=`find ext -type f \( -name '*.h' -o -name '*.c' \)`
for i in $SOURCE_FILES
do
$CLANG_FORMAT -output-replacements-xml $i | grep -c "<replacement " > /dev/null
View File
+26 -23
View File
@@ -1,21 +1,33 @@
<?php
namespace AWS\CRT;
use AWS\CRT\Internal\Extension;
use AWS\CRT\Internal\FFI;
use \RuntimeException;
/**
* Wrapper for the FFI interface to the CRT. There only ever needs to be one of these.
* Wrapper for the interface to the CRT. There only ever needs to be one of these, but
* additional instances won't cost anything other than their memory.
* Creating an instance of any NativeResource will activate the CRT binding. User code
* should only need to create one of these if they are only accessing CRT:: functions.
* should only need to create one of these if they are only accessing CRT:: static functions.
*/
final class CRT {
private static $ffi = null;
private static $impl = null;
private static $refcount = 0;
function __construct() {
if (is_null(self::$ffi)) {
if (is_null(self::$impl)) {
try {
self::$ffi = FFI::cdef(file_get_contents(__DIR__ . "/../api.h"), __DIR__ . "/../libaws-crt-ffi.so");
self::init();
} catch (Exception $e) {
echo 'Exception while initializing CRT via FFI: ', $e->getMessage(), "\n";
self::$impl = new Extension();
} catch (RuntimeException $rex) {
try {
self::$impl = new FFI();
} catch (RuntimeException $frex) {
throw new RuntimeException('Unable to initialize AWS CRT via extension or FFI', -1, $frex);
}
}
}
++self::$refcount;
@@ -23,24 +35,15 @@ final class CRT {
function __destruct() {
if (--self::$refcount == 0) {
self::clean_up();
self::$ffi = null;
self::$impl = null;
}
}
private static function init() {
return self::$ffi->aws_crt_init();
}
private static function clean_up() {
return self::$ffi->aws_crt_clean_up();
}
/**
* @return integer last error code reported within the CRT
*/
public static function last_error() {
return self::$ffi->aws_crt_last_error();
return self::$impl->aws_crt_last_error();
}
/**
@@ -48,7 +51,7 @@ final class CRT {
* @return string Human-readable description of the provided error code
*/
public static function error_str($error) {
return self::$ffi->aws_crt_error_str((int) $error);
return self::$impl->aws_crt_error_str((int) $error);
}
/**
@@ -56,14 +59,14 @@ final class CRT {
* @return string Name/enum identifier for the provided error code
*/
public static function error_name($error) {
return self::$ffi->aws_crt_error_name((int) $error);
return self::$impl->aws_crt_error_name((int) $error);
}
function event_loop_group_new($num_threads) {
return self::$ffi->aws_crt_event_loop_group_new($num_threads);
return self::$impl->aws_crt_event_loop_group_new($num_threads);
}
function event_loop_group_release($elg) {
return self::$ffi->aws_crt_event_loop_group_release($elg);
return self::$impl->aws_crt_event_loop_group_release($elg);
}
}
@@ -1,5 +1,9 @@
<?php
namespace AWS\CRT\IO;
use AWS\CRT\NativeResource as NativeResource;
/**
* Represents 1 or more event loops (1 per thread) for doing I/O and background tasks.
* Typically, every application has one EventLoopGroup.
@@ -24,8 +28,7 @@ final class EventLoopGroup extends NativeResource {
}
function __destruct() {
self::$crt->event_loop_group_release($this->native);
$this->release();
self::$crt->event_loop_group_release($this->release());
parent::__destruct();
}
}
+26
View File
@@ -0,0 +1,26 @@
<?php
namespace AWS\CRT\Internal;
use \RuntimeException;
/**
* @internal
* Forwards calls on to awscrt PHP extension functions
*/
final class Extension {
function __construct() {
if (!extension_loaded('awscrt')) {
throw new RuntimeException('awscrt extension is not loaded');
}
}
/**
* Forwards any call made on this object to the extension function of the
* same name with the supplied arguments. Argument type hinting and checking
* occurs at the CRT wrapper.
*/
function __call(string $name, $args) {
return call_user_func_array($name, $args);
}
}
+51
View File
@@ -0,0 +1,51 @@
<?php
namespace AWS\CRT\Internal;
use \Exception;
use \RuntimeException;
/**
* @internal
* Forwards calls on to libaws-crt-ffi via FFI
*/
final class FFI {
private static $ffi = null;
private static $refcount = 0;
function __construct() {
if (is_null(self::$ffi)) {
try {
self::$ffi = \FFI::cdef(file_get_contents(__DIR__ . "/../../../api.h"), __DIR__ . "/../../../libaws-crt-ffi.so");
self::init();
} catch (Exception $e) {
throw new RuntimeException('Exception while initializing CRT via FFI', 0, $e);
}
}
++self::$refcount;
}
function __destruct() {
if (--self::$refcount == 0) {
self::clean_up();
self::$ffi = null;
}
}
/**
* Forwards any call made on this object to the FFI function of the
* same name with the supplied arguments. Argument type hinting and checking
* occurs at the CRT wrapper.
*/
function __call(string $name, $args) {
return call_user_func_array(array(self::$ffi, $name), $args);
}
private static function init() {
return self::$ffi->aws_crt_init();
}
private static function clean_up() {
return self::$ffi->aws_crt_clean_up();
}
}
@@ -1,5 +1,9 @@
<?php
namespace AWS\CRT;
use AWS\CRT\CRT as CRT;
/**
* Base class for all native resources, tracks all outstanding resources
* and provides basic leak checking
@@ -11,11 +15,7 @@ abstract class NativeResource {
function __construct() {
if (is_null(self::$crt)) {
try {
self::$crt = new CRT();
} catch (Exception $e) {
echo 'Exception while loading CRT: ', $e->getMessage(), "\n";
}
self::$crt = new CRT();
}
self::$resources[spl_object_hash($this)] = 1;
@@ -26,7 +26,9 @@ abstract class NativeResource {
}
protected function release() {
$native = $this->native;
$this->native = null;
return $native;
}
function __destruct() {
View File
@@ -1,5 +1,7 @@
<?php
use AWS\CRT\CRT;
final class ErrorTest extends PHPUnit_Framework_TestCase {
private static $crt = null;
public static function setUpBeforeClass() {
@@ -1,9 +1,12 @@
<?php
use AWS\CRT\IO\EventLoopGroup as EventLoopGroup;
final class EventLoopGroupTest extends PHPUnit_Framework_TestCase {
public function testLifetime() {
$elg = new EventLoopGroup();
$this->assertNotNull($elg, "Failed to create default EventLoopGroup");
$elg = null;
}
@@ -11,6 +14,7 @@ final class EventLoopGroupTest extends PHPUnit_Framework_TestCase {
$options = EventLoopGroup::defaults();
$options['num_threads'] = 1;
$elg = new EventLoopGroup($options);
$this->assertNotNull($elg, "Failed to create EventLoopGroup with 1 thread");
$elg = null;
}
}