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/ .libs/
build/ build/
configure.in configure.in
configure.ac
mkinstalldirs mkinstalldirs
run-tests.php run-tests.php
Makefile.global 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 $(BUILD_DIR)/aws-crt-ffi/libaws-crt-ffi.so: $(BUILD_DIR)/aws-crt-ffi/CMakeCache.txt
$(CMAKE_BUILD) build/aws-crt-ffi $(CMAKE_TARGET) $(CMAKE_BUILD) build/aws-crt-ffi $(CMAKE_TARGET)
# copy the lib into the lib folder # copy the lib into the src folder
$(INSTALL_DIR)/lib/libaws-crt-ffi.so: $(BUILD_DIR)/aws-crt-ffi/libaws-crt-ffi.so $(INSTALL_DIR)/lib/api.h $(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)/lib/libaws-crt-ffi.so 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 api.h from FFI lib
$(INSTALL_DIR)/lib/api.h: crt/aws-crt-ffi/src/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)/lib/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 # 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) ifeq ($(TEST_FFI),1)
test-ci: test-ffi test-ci: test-ffi
@@ -58,6 +62,6 @@ test-ci: test
endif endif
# Test the FFI interface # 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 update
composer run test composer run test
+4 -7
View File
@@ -12,19 +12,16 @@
}, },
"autoload": { "autoload": {
"classmap": [ "classmap": [
"lib/" "src/"
], ]
"psr-4": {
"AWS\\": "lib/AWS"
}
}, },
"autoload-dev": { "autoload-dev": {
"classmap": [ "classmap": [
"lib/tests/" "src/tests/"
] ]
}, },
"scripts": { "scripts": {
"test": "phpunit lib/tests" "test": "phpunit src/tests"
}, },
"license": "Apache-2.0", "license": "Apache-2.0",
"authors": [ "authors": [
+1 -1
View File
@@ -17,7 +17,7 @@ if test "$PHP_AWSCRT" != "no"; then
PHP_SUBST(AWSCRT_SHARED_LIBADD) PHP_SUBST(AWSCRT_SHARED_LIBADD)
# Sources for the PHP extension itself # Sources for the PHP extension itself
AWSCRT_SOURCES=src/*.c AWSCRT_SOURCES=ext/*.c
PHP_NEW_EXTENSION(awscrt, $AWSCRT_SOURCES, $ext_shared) PHP_NEW_EXTENSION(awscrt, $AWSCRT_SOURCES, $ext_shared)
fi 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 fi
FAIL=0 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 for i in $SOURCE_FILES
do do
$CLANG_FORMAT -output-replacements-xml $i | grep -c "<replacement " > /dev/null $CLANG_FORMAT -output-replacements-xml $i | grep -c "<replacement " > /dev/null
View File
+26 -23
View File
@@ -1,21 +1,33 @@
<?php <?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 * 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 { final class CRT {
private static $ffi = null;
private static $impl = null;
private static $refcount = 0; private static $refcount = 0;
function __construct() { function __construct() {
if (is_null(self::$ffi)) { if (is_null(self::$impl)) {
try { try {
self::$ffi = FFI::cdef(file_get_contents(__DIR__ . "/../api.h"), __DIR__ . "/../libaws-crt-ffi.so"); self::$impl = new Extension();
self::init(); } catch (RuntimeException $rex) {
} catch (Exception $e) { try {
echo 'Exception while initializing CRT via FFI: ', $e->getMessage(), "\n"; self::$impl = new FFI();
} catch (RuntimeException $frex) {
throw new RuntimeException('Unable to initialize AWS CRT via extension or FFI', -1, $frex);
}
} }
} }
++self::$refcount; ++self::$refcount;
@@ -23,24 +35,15 @@ final class CRT {
function __destruct() { function __destruct() {
if (--self::$refcount == 0) { if (--self::$refcount == 0) {
self::clean_up(); self::$impl = null;
self::$ffi = 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 * @return integer last error code reported within the CRT
*/ */
public static function last_error() { 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 * @return string Human-readable description of the provided error code
*/ */
public static function error_str($error) { 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 * @return string Name/enum identifier for the provided error code
*/ */
public static function error_name($error) { 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) { 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) { 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 <?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. * Represents 1 or more event loops (1 per thread) for doing I/O and background tasks.
* Typically, every application has one EventLoopGroup. * Typically, every application has one EventLoopGroup.
@@ -24,8 +28,7 @@ final class EventLoopGroup extends NativeResource {
} }
function __destruct() { function __destruct() {
self::$crt->event_loop_group_release($this->native); self::$crt->event_loop_group_release($this->release());
$this->release();
parent::__destruct(); 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 <?php
namespace AWS\CRT;
use AWS\CRT\CRT as CRT;
/** /**
* Base class for all native resources, tracks all outstanding resources * Base class for all native resources, tracks all outstanding resources
* and provides basic leak checking * and provides basic leak checking
@@ -11,11 +15,7 @@ abstract class NativeResource {
function __construct() { function __construct() {
if (is_null(self::$crt)) { if (is_null(self::$crt)) {
try {
self::$crt = new CRT(); self::$crt = new CRT();
} catch (Exception $e) {
echo 'Exception while loading CRT: ', $e->getMessage(), "\n";
}
} }
self::$resources[spl_object_hash($this)] = 1; self::$resources[spl_object_hash($this)] = 1;
@@ -26,7 +26,9 @@ abstract class NativeResource {
} }
protected function release() { protected function release() {
$native = $this->native;
$this->native = null; $this->native = null;
return $native;
} }
function __destruct() { function __destruct() {
View File
@@ -1,5 +1,7 @@
<?php <?php
use AWS\CRT\CRT;
final class ErrorTest extends PHPUnit_Framework_TestCase { final class ErrorTest extends PHPUnit_Framework_TestCase {
private static $crt = null; private static $crt = null;
public static function setUpBeforeClass() { public static function setUpBeforeClass() {
@@ -1,9 +1,12 @@
<?php <?php
use AWS\CRT\IO\EventLoopGroup as EventLoopGroup;
final class EventLoopGroupTest extends PHPUnit_Framework_TestCase { final class EventLoopGroupTest extends PHPUnit_Framework_TestCase {
public function testLifetime() { public function testLifetime() {
$elg = new EventLoopGroup(); $elg = new EventLoopGroup();
$this->assertNotNull($elg, "Failed to create default EventLoopGroup");
$elg = null; $elg = null;
} }
@@ -11,6 +14,7 @@ final class EventLoopGroupTest extends PHPUnit_Framework_TestCase {
$options = EventLoopGroup::defaults(); $options = EventLoopGroup::defaults();
$options['num_threads'] = 1; $options['num_threads'] = 1;
$elg = new EventLoopGroup($options); $elg = new EventLoopGroup($options);
$this->assertNotNull($elg, "Failed to create EventLoopGroup with 1 thread");
$elg = null; $elg = null;
} }
} }