Code Monkey home page Code Monkey logo

swoole-cli's Introduction

Swoole Logo
Swoole is an event-driven, asynchronous, coroutine-based concurrency library with high performance for PHP.

lib-swoole ext-swoole test-linux Frameworks Tests codecov

Twitter Discord Latest Release License Coverity Scan Build Status

⚙️ Quick Start

Run Swoole program by Docker

docker run --rm phpswoole/swoole "php --ri swoole"

For details on how to use it, see: How to Use This Image.

Documentation

https://wiki.swoole.com/

HTTP Service

$http = new Swoole\Http\Server('127.0.0.1', 9501);
$http->set(['hook_flags' => SWOOLE_HOOK_ALL]);

$http->on('request', function ($request, $response) {
    $result = [];
    Co::join([
        go(function () use (&$result) {
            $result['google'] = file_get_contents("https://www.google.com/");
        }),
        go(function () use (&$result) {
            $result['taobao'] = file_get_contents("https://www.taobao.com/");
        })
    ]);
    $response->end(json_encode($result));
});

$http->start();

Concurrency

Co\run(function() {
    Co\go(function() {
        while(1) {
            sleep(1);
            $fp = stream_socket_client("tcp://127.0.0.1:8000", $errno, $errstr, 30);
            echo fread($fp, 8192), PHP_EOL;
        }
    });

    Co\go(function() {
        $fp = stream_socket_server("tcp://0.0.0.0:8000", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN);
        while(1) {
            $conn = stream_socket_accept($fp);
            fwrite($conn, 'The local time is ' . date('n/j/Y g:i a'));
        }
    });

    Co\go(function() {
        $redis = new Redis();
        $redis->connect('127.0.0.1', 6379);
        while(true) {
            $redis->subscribe(['test'], function ($instance, $channelName, $message) {
                echo 'New redis message: '.$channelName, "==>", $message, PHP_EOL;
            });
        }
    });

    Co\go(function() {
        $redis = new Redis();
        $redis->connect('127.0.0.1', 6379);
        $count = 0;
        while(true) {
            sleep(2);
            $redis->publish('test','hello, world, count='.$count++);
        }
    });
});

Runtime Hook

Swoole hooks the blocking io function of PHP at the bottom layer and automatically converts it to a non-blocking function, so that these functions can be called concurrently in coroutines.

Supported extension/functions

  • ext-curl (Support symfony and guzzle)
  • ext-redis
  • ext-mysqli
  • ext-pdo_mysql
  • ext-pdo_pgsql
  • ext-pdo_sqlite
  • ext-pdo_oracle
  • ext-pdo_odbc
  • stream functions (e.g. stream_socket_client/stream_socket_server), Supports TCP/UDP/UDG/Unix/SSL/TLS/FileSystem API/Pipe
  • ext-sockets
  • ext-soap
  • sleep/usleep/time_sleep_until
  • proc_open
  • gethostbyname/shell_exec/exec
  • fread/fopen/fsockopen/fwrite/flock

🛠 Develop & Discussion

💎 Awesome Swoole

Project Awesome Swoole maintains a curated list of awesome things related to Swoole, including

  • Swoole-based frameworks and libraries.
  • Packages to integrate Swoole with popular PHP frameworks, including Laravel, Symfony, Slim, and Yii.
  • Books, videos, and other learning materials about Swoole.
  • Debugging, profiling, and testing tools for developing Swoole-based applications.
  • Coroutine-friendly packages and libraries.
  • Other Swoole related projects and resources.

✨ Event-based

The network layer in Swoole is event-based and takes full advantage of the underlying epoll/kqueue implementation, making it really easy to serve millions of requests.

Swoole 4.x uses a brand new engine kernel and now it has a full-time developer team, so we are entering an unprecedented period in PHP history which offers a unique possibility for rapid evolution in performance.

⚡ Coroutine

Swoole 4.x or later supports the built-in coroutine with high availability, and you can use fully synchronized code to implement asynchronous performance. PHP code without any additional keywords, the underlying automatic coroutine-scheduling.

Developers can understand coroutines as ultra-lightweight threads, and you can easily create thousands of coroutines in a single process.

MySQL

Concurrency 10K requests to read data from MySQL takes only 0.2s!

$s = microtime(true);
Co\run(function() {
    for ($c = 100; $c--;) {
        go(function () {
            $mysql = new Swoole\Coroutine\MySQL;
            $mysql->connect([
                'host' => '127.0.0.1',
                'user' => 'root',
                'password' => 'root',
                'database' => 'test'
            ]);
            $statement = $mysql->prepare('SELECT * FROM `user`');
            for ($n = 100; $n--;) {
                $result = $statement->execute();
                assert(count($result) > 0);
            }
        });
    }
});
echo 'use ' . (microtime(true) - $s) . ' s';

Mixed server

You can create multiple services on the single event loop: TCP, HTTP, Websocket and HTTP2, and easily handle thousands of requests.

function tcp_pack(string $data): string
{
    return pack('N', strlen($data)) . $data;
}
function tcp_unpack(string $data): string
{
    return substr($data, 4, unpack('N', substr($data, 0, 4))[1]);
}
$tcp_options = [
    'open_length_check' => true,
    'package_length_type' => 'N',
    'package_length_offset' => 0,
    'package_body_offset' => 4
];
$server = new Swoole\WebSocket\Server('127.0.0.1', 9501, SWOOLE_BASE);
$server->set(['open_http2_protocol' => true]);
// http && http2
$server->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response) {
    $response->end('Hello ' . $request->rawcontent());
});
// websocket
$server->on('message', function (Swoole\WebSocket\Server $server, Swoole\WebSocket\Frame $frame) {
    $server->push($frame->fd, 'Hello ' . $frame->data);
});
// tcp
$tcp_server = $server->listen('127.0.0.1', 9502, SWOOLE_TCP);
$tcp_server->set($tcp_options);
$tcp_server->on('receive', function (Swoole\Server $server, int $fd, int $reactor_id, string $data) {
    $server->send($fd, tcp_pack('Hello ' . tcp_unpack($data)));
});
$server->start();

Coroutine clients

Whether you DNS query or send requests or receive responses, all of these are scheduled by coroutine automatically.

go(function () {
    // http
    $http_client = new Swoole\Coroutine\Http\Client('127.0.0.1', 9501);
    assert($http_client->post('/', 'Swoole Http'));
    var_dump($http_client->body);
    // websocket
    $http_client->upgrade('/');
    $http_client->push('Swoole Websocket');
    var_dump($http_client->recv()->data);
});
go(function () {
    // http2
    $http2_client = new Swoole\Coroutine\Http2\Client('localhost', 9501);
    $http2_client->connect();
    $http2_request = new Swoole\Http2\Request;
    $http2_request->method = 'POST';
    $http2_request->data = 'Swoole Http2';
    $http2_client->send($http2_request);
    $http2_response = $http2_client->recv();
    var_dump($http2_response->data);
});
go(function () use ($tcp_options) {
    // tcp
    $tcp_client = new Swoole\Coroutine\Client(SWOOLE_TCP);
    $tcp_client->set($tcp_options);
    $tcp_client->connect('127.0.0.1', 9502);
    $tcp_client->send(tcp_pack('Swoole Tcp'));
    var_dump(tcp_unpack($tcp_client->recv()));
});

Channel

Channel is the only way for exchanging data between coroutines, the development combination of the Coroutine + Channel is the famous CSP programming model.

In Swoole development, Channel is usually used for implementing connection pool or scheduling coroutine concurrent.

The simplest example of a connection pool

In the following example, we have a thousand concurrently requests to redis. Normally, this has exceeded the maximum number of Redis connections setting and will throw a connection exception, but the connection pool based on Channel can perfectly schedule requests. We don't have to worry about connection overload.

class RedisPool
{
    /**@var \Swoole\Coroutine\Channel */
    protected $pool;

    /**
     * RedisPool constructor.
     * @param int $size max connections
     */
    public function __construct(int $size = 100)
    {
        $this->pool = new \Swoole\Coroutine\Channel($size);
        for ($i = 0; $i < $size; $i++) {
            $redis = new \Swoole\Coroutine\Redis();
            $res = $redis->connect('127.0.0.1', 6379);
            if ($res == false) {
                throw new \RuntimeException("failed to connect redis server.");
            } else {
                $this->put($redis);
            }
        }
    }

    public function get(): \Swoole\Coroutine\Redis
    {
        return $this->pool->pop();
    }

    public function put(\Swoole\Coroutine\Redis $redis)
    {
        $this->pool->push($redis);
    }

    public function close(): void
    {
        $this->pool->close();
        $this->pool = null;
    }
}

go(function () {
    $pool = new RedisPool();
    // max concurrency num is more than max connections
    // but it's no problem, channel will help you with scheduling
    for ($c = 0; $c < 1000; $c++) {
        go(function () use ($pool, $c) {
            for ($n = 0; $n < 100; $n++) {
                $redis = $pool->get();
                assert($redis->set("awesome-{$c}-{$n}", 'swoole'));
                assert($redis->get("awesome-{$c}-{$n}") === 'swoole');
                assert($redis->delete("awesome-{$c}-{$n}"));
                $pool->put($redis);
            }
        });
    }
});

Producer and consumers

Some Swoole's clients implement the defer mode for concurrency, but you can still implement it flexible with a combination of coroutines and channels.

go(function () {
    // User: I need you to bring me some information back.
    // Channel: OK! I will be responsible for scheduling.
    $channel = new Swoole\Coroutine\Channel;
    go(function () use ($channel) {
        // Coroutine A: Ok! I will show you the github addr info
        $addr_info = Co::getaddrinfo('github.com');
        $channel->push(['A', json_encode($addr_info, JSON_PRETTY_PRINT)]);
    });
    go(function () use ($channel) {
        // Coroutine B: Ok! I will show you what your code look like
        $mirror = Co::readFile(__FILE__);
        $channel->push(['B', $mirror]);
    });
    go(function () use ($channel) {
        // Coroutine C: Ok! I will show you the date
        $channel->push(['C', date(DATE_W3C)]);
    });
    for ($i = 3; $i--;) {
        list($id, $data) = $channel->pop();
        echo "From {$id}:\n {$data}\n";
    }
    // User: Amazing, I got every information at earliest time!
});

Timer

$id = Swoole\Timer::tick(100, function () {
    echo "⚙️ Do something...\n";
});
Swoole\Timer::after(500, function () use ($id) {
    Swoole\Timer::clear($id);
    echo "⏰ Done\n";
});
Swoole\Timer::after(1000, function () use ($id) {
    if (!Swoole\Timer::exists($id)) {
        echo "✅ All right!\n";
    }
});

The way of coroutine

go(function () {
    $i = 0;
    while (true) {
        Co::sleep(0.1);
        echo "📝 Do something...\n";
        if (++$i === 5) {
            echo "🛎 Done\n";
            break;
        }
    }
    echo "🎉 All right!\n";
});

🔥 Amazing runtime hooks

As of Swoole v4.1.0, we added the ability to transform synchronous PHP network libraries into co-routine libraries using a single line of code.

Simply call the Swoole\Runtime::enableCoroutine() method at the top of your script. In the sample below we connect to php-redis and concurrently read 10k requests in 0.1s:

Swoole\Runtime::enableCoroutine();
$s = microtime(true);
Co\run(function() {
    for ($c = 100; $c--;) {
        go(function () {
            ($redis = new Redis)->connect('127.0.0.1', 6379);
            for ($n = 100; $n--;) {
                assert($redis->get('awesome') === 'swoole');
            }
        });
    }
});
echo 'use ' . (microtime(true) - $s) . ' s';

By calling this method, the Swoole kernel replaces ZendVM stream function pointers. If you use php_stream based extensions, all socket operations can be dynamically converted to be asynchronous IO scheduled by coroutine at runtime!

How many things you can do in 1s?

Sleep 10K times, read, write, check and delete files 10K times, use PDO and MySQLi to communicate with the database 10K times, create a TCP server and multiple clients to communicate with each other 10K times, create a UDP server and multiple clients to communicate with each other 10K times... Everything works well in one process!

Just see what the Swoole brings, just imagine...

Swoole\Runtime::enableCoroutine();
$s = microtime(true);
Co\run(function() {
    // i just want to sleep...
    for ($c = 100; $c--;) {
        go(function () {
            for ($n = 100; $n--;) {
                usleep(1000);
            }
        });
    }

    // 10K file read and write
    for ($c = 100; $c--;) {
        go(function () use ($c) {
            $tmp_filename = "/tmp/test-{$c}.php";
            for ($n = 100; $n--;) {
                $self = file_get_contents(__FILE__);
                file_put_contents($tmp_filename, $self);
                assert(file_get_contents($tmp_filename) === $self);
            }
            unlink($tmp_filename);
        });
    }

    // 10K pdo and mysqli read
    for ($c = 50; $c--;) {
        go(function () {
            $pdo = new PDO('mysql:host=127.0.0.1;dbname=test;charset=utf8', 'root', 'root');
            $statement = $pdo->prepare('SELECT * FROM `user`');
            for ($n = 100; $n--;) {
                $statement->execute();
                assert(count($statement->fetchAll()) > 0);
            }
        });
    }
    for ($c = 50; $c--;) {
        go(function () {
            $mysqli = new Mysqli('127.0.0.1', 'root', 'root', 'test');
            $statement = $mysqli->prepare('SELECT `id` FROM `user`');
            for ($n = 100; $n--;) {
                $statement->bind_result($id);
                $statement->execute();
                $statement->fetch();
                assert($id > 0);
            }
        });
    }

    // php_stream tcp server & client with 12.8K requests in single process
    function tcp_pack(string $data): string
    {
        return pack('n', strlen($data)) . $data;
    }

    function tcp_length(string $head): int
    {
        return unpack('n', $head)[1];
    }

    go(function () {
        $ctx = stream_context_create(['socket' => ['so_reuseaddr' => true, 'backlog' => 128]]);
        $socket = stream_socket_server(
            'tcp://0.0.0.0:9502',
            $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctx
        );
        if (!$socket) {
            echo "$errstr ($errno)\n";
        } else {
            $i = 0;
            while ($conn = stream_socket_accept($socket, 1)) {
                stream_set_timeout($conn, 5);
                for ($n = 100; $n--;) {
                    $data = fread($conn, tcp_length(fread($conn, 2)));
                    assert($data === "Hello Swoole Server #{$n}!");
                    fwrite($conn, tcp_pack("Hello Swoole Client #{$n}!"));
                }
                if (++$i === 128) {
                    fclose($socket);
                    break;
                }
            }
        }
    });
    for ($c = 128; $c--;) {
        go(function () {
            $fp = stream_socket_client("tcp://127.0.0.1:9502", $errno, $errstr, 1);
            if (!$fp) {
                echo "$errstr ($errno)\n";
            } else {
                stream_set_timeout($fp, 5);
                for ($n = 100; $n--;) {
                    fwrite($fp, tcp_pack("Hello Swoole Server #{$n}!"));
                    $data = fread($fp, tcp_length(fread($fp, 2)));
                    assert($data === "Hello Swoole Client #{$n}!");
                }
                fclose($fp);
            }
        });
    }

    // udp server & client with 12.8K requests in single process
    go(function () {
        $socket = new Swoole\Coroutine\Socket(AF_INET, SOCK_DGRAM, 0);
        $socket->bind('127.0.0.1', 9503);
        $client_map = [];
        for ($c = 128; $c--;) {
            for ($n = 0; $n < 100; $n++) {
                $recv = $socket->recvfrom($peer);
                $client_uid = "{$peer['address']}:{$peer['port']}";
                $id = $client_map[$client_uid] = ($client_map[$client_uid] ?? -1) + 1;
                assert($recv === "Client: Hello #{$id}!");
                $socket->sendto($peer['address'], $peer['port'], "Server: Hello #{$id}!");
            }
        }
        $socket->close();
    });
    for ($c = 128; $c--;) {
        go(function () {
            $fp = stream_socket_client("udp://127.0.0.1:9503", $errno, $errstr, 1);
            if (!$fp) {
                echo "$errstr ($errno)\n";
            } else {
                for ($n = 0; $n < 100; $n++) {
                    fwrite($fp, "Client: Hello #{$n}!");
                    $recv = fread($fp, 1024);
                    list($address, $port) = explode(':', (stream_socket_get_name($fp, true)));
                    assert($address === '127.0.0.1' && (int)$port === 9503);
                    assert($recv === "Server: Hello #{$n}!");
                }
                fclose($fp);
            }
        });
    }
});
echo 'use ' . (microtime(true) - $s) . ' s';

⌛️ Installation

As with any open source project, Swoole always provides the most reliable stability and the most powerful features in the latest released version. Please ensure as much as possible that you are using the latest version.

Compiling requirements

  • Linux, OS X or Cygwin, WSL
  • PHP 7.2.0 or later (The higher the version, the better the performance.)
  • GCC 4.8 or later

1. Install via PECL (beginners)

pecl install swoole

2. Install from source (recommended)

Please download the source packages from Releases or:

git clone https://github.com/swoole/swoole-src.git && \
cd swoole-src

Compile and install at the source folder:

phpize && \
./configure && \
make && make install

Enable extension in PHP

After compiling and installing to the system successfully, you have to add a new line extension=swoole.so to php.ini to enable Swoole extension.

Extra compiler configurations

for example: ./configure --enable-openssl --enable-sockets

  • --enable-openssl or --with-openssl-dir=DIR
  • --enable-sockets
  • --enable-mysqlnd (need mysqlnd, it just for supporting $mysql->escape method)
  • --enable-swoole-curl

Upgrade

⚠️ If you upgrade from source, don't forget to make clean before you upgrade your swoole

  1. pecl upgrade swoole
  2. cd swoole-src && git pull && make clean && make && sudo make install
  3. if you change your PHP version, please re-run phpize clean && phpize then try to compile

Major change since version 4.3.0

Async clients and API are moved to a separate PHP extension swoole_async since version 4.3.0, install swoole_async:

git clone https://github.com/swoole/ext-async.git
cd ext-async
phpize
./configure
make -j 4
sudo make install

Enable it by adding a new line extension=swoole_async.so to php.ini.

🍭 Benchmark

  • On the open source Techempower Web Framework benchmarks Swoole used MySQL database benchmark to rank first, and all performance tests ranked in the first echelon.
  • You can just run Benchmark Script to quickly test the maximum QPS of Swoole-HTTP-Server on your machine.

🔰️ Security issues

Security issues should be reported privately, via email, to the Swoole develop team [email protected]. You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message.

🖊️ Contribution

Your contribution to Swoole development is very welcome!

You may contribute in the following ways:

❤️ Contributors

This project exists thanks to all the people who contribute. [Contributors].

🎙️ Official Evangelist

Demin has been playing with PHP since 2000, focusing on building high-performance, secure web services. He is an occasional conference speaker on PHP and Swoole, and has been working for companies in the states like eBay, Visa and Glu Mobile for years. You may find Demin on Twitter or GitHub.

📃 License

Apache License Version 2.0 see http://www.apache.org/licenses/LICENSE-2.0.html

swoole-cli's People

Contributors

amuluowin avatar coketsang avatar cotch22 avatar ganl avatar jingjingxyk avatar kauruus avatar matyhtf avatar try-to avatar yurunsoft avatar yvesho0968 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

swoole-cli's Issues

执行 make clean 时会删除 thirdparty 中的目标文件

如题,待解决

考虑借鉴 phpbrew ,创建一个 $HOME/.swoole-cli/ 目录,存储下载、构建以及目标文件

  • $HOME/.swoole-cli/source:源代码包,替换当前的 pool/libpool/ext
  • $HOME/.swoole-cli/build:构建时文件,替换当前的 thirdparty 目录
  • $HOME/.swoole-cli/library:在 macOS 系统下替换 /usr 目录

提示:macOS 上启用opcache 建议添加 --disable-opcache-jit 参数

起因:
macOS 上启用opcache ,发现启用JIT 时,编译通过不了。进一步查看,发现会自动依赖库 capstone 、dynasm 等

#if defined(HAVE_DISASM) || defined(HAVE_GDB) || defined(HAVE_OPROFILE) || defined(HAVE_PERFTOOLS) || defined(HAVE_VTUNE)



另外一种解决办法是 卸载本机的 capstone dynasm 库

提示: macOS 链接时libxslt 需要添加 -framework CoreFoundation -framework SystemConfiguration 原因所在

macOS 反复验证:
发现 依赖库libxslt 默认启用 --with-python --with-crypto --with-profiler --with-plugins --with-debugger
其中 crypto 依赖 libunistring 、libgcrypt 进一步依赖 -framework SystemConfiguration

根源: -lintl -Wl,-framework -Wl,CoreFoundation

gettext库包含intl
coreutils库包含libunistring

解决办法:

    ./configure \
    --prefix={$libxslt_prefix} \
    --enable-static=yes \
    --enable-shared=no \
    --with-libxml-libs-prefix={$libxml2_prefix} \
    --without-python \
    --without-crypto \
    --without-profiler \
    --without-plugins \
    --without-debugger

解决以后,链接参数就可以不需要

-framework CoreFoundation -framework SystemConfiguration 

不修改本仓库源码前提下,添加内置扩展 ffi 、pdo_pgsql、pgsql 参考

自己新增内置扩展,同时又不修改本仓库源代码
install_php_internal_extensions

function ($p)
{

    $workDir = $p->getWorkDir();
    $p->addLibrary(
        (new Library('php_internal_extensions'))
            ->withHomePage('https://www.php.net/')
            ->withLicense('https://github.com/php/php-src/blob/master/LICENSE', Library::LICENSE_PHP)
            ->withUrl('https://github.com/php/php-src/archive/refs/tags/php-8.1.12.tar.gz')
            ->withFile('php-8.1.12.tar.gz')
            ->withManual('https://www.php.net/docs.php')
            ->withLabel('php_internal_extension')
            ->withCleanBuildDirectory()
            ->withScriptBeforeConfigure(
                "
                    test -d {$workDir}/ext/ffi && rm -rf {$workDir}/ext/ffi
                    cp -rf  ext/ffi {$workDir}/ext/
                    
                    test -d {$workDir}/ext/pdo_pgsql && rm -rf {$workDir}/ext/pdo_pgsql
                    cp -rf  ext/pdo_pgsql {$workDir}/ext/
                    
                    test -d {$workDir}/ext/pgsql && rm -rf {$workDir}/ext/pgsql
                    cp -rf  ext/pgsql {$workDir}/ext/
                "
            )
            ->withConfigure('return 0')
            ->disablePkgName()
            ->disableDefaultPkgConfig()
            ->disableDefaultLdflags()
            ->withSkipBuildLicense()

    );

}

静态编译libpq,libffi参考

静态编译libpq源代码

function install_pgsql(Preprocessor $p)
{
    $p->addLibrary(
        (new Library('pgsql'))
            ->withHomePage('https://www.postgresql.org/')
            ->withLicense('https://www.postgresql.org/about/licence/', Library::LICENSE_SPEC)
            ->withUrl('https://ftp.postgresql.org/pub/source/v15.1/postgresql-15.1.tar.gz')
            //https://www.postgresql.org/docs/devel/installation.html
            //https://www.postgresql.org/docs/devel/install-make.html#INSTALL-PROCEDURE-MAKE
            ->withManual('https://www.postgresql.org/docs/')
            ->withCleanBuildDirectory()
            ->withScriptBeforeConfigure(
                '
               test -d /usr/pgsql && rm -rf /usr/pgsql
            '
            )
            ->withConfigure(
                '
            ./configure --help
            
            sed -i.backup "s/invokes exit\'; exit 1;/invokes exit\';/"  src/interfaces/libpq/Makefile
  
            # 替换指定行内容
            sed -i.backup "102c all: all-lib" src/interfaces/libpq/Makefile
           
            # export CPPFLAGS="-static -fPIE -fPIC -O2 -Wall "
            # export CFLAGS="-static -fPIE -fPIC -O2 -Wall "
            
            export CPPFLAGS=$(pkg-config  --cflags --static  icu-uc icu-io icu-i18n readline libxml-2.0)
            export LIBS=$(pkg-config  --libs --static   icu-uc icu-io icu-i18n readline libxml-2.0)
          
         
            ./configure  --prefix=/usr/pgsql \
            --enable-coverage=no \
            --with-ssl=openssl  \
            --with-readline \
            --with-icu \
            --without-ldap \
            --with-libxml  \
            --with-libxslt \
            --with-includes="/usr/openssl/include/:/usr/libxml2/include/:/usr/libxslt/include:/usr/readline/include/readline:/usr/icu/include:/usr/zlib/include:/usr/include" \
            --with-libraries="/usr/openssl/lib:/usr/libxml2/lib/:/usr/libxslt/lib/:/usr/readline/lib:/usr/icu/lib:/usr/zlib/lib:/usr/lib"

            make -C src/include install 
            result_code=$?
            [[ $result_code -ne 0 ]] && echo "[make FAILURE]" && exit $result_code;
            
            make -C  src/bin/pg_config install
            result_code=$?
            [[ $result_code -ne 0 ]] && echo "[make FAILURE]" && exit $result_code;
            
            
            make -C  src/common -j $cpu_nums all 
            make -C  src/common install 
            result_code=$?
            [[ $result_code -ne 0 ]] && echo "[make FAILURE]" && exit $result_code;
            
            make -C  src/port -j $cpu_nums all 
            make -C  src/port install 
            result_code=$?
            [[ $result_code -ne 0 ]] && echo "[make FAILURE]" && exit $result_code;
                        
            make -C  src/backend/libpq -j $cpu_nums all 
            make -C  src/backend/libpq install 
            result_code=$?
            [[ $result_code -ne 0 ]] && echo "[make FAILURE]" && exit $result_code;
                        
            make -C src/interfaces/ecpg   -j $cpu_nums all-pgtypeslib-recurse all-ecpglib-recurse all-compatlib-recurse all-preproc-recurse
            make -C src/interfaces/ecpg  install-pgtypeslib-recurse install-ecpglib-recurse install-compatlib-recurse install-preproc-recurse
            result_code=$?
            [[ $result_code -ne 0 ]] && echo "[make FAILURE]" && exit $result_code;
                        
            # 静态编译 src/interfaces/libpq/Makefile  有静态配置  参考: all-static-lib
            
            make -C src/interfaces/libpq  -j $cpu_nums # soname=true
            make -C src/interfaces/libpq  install 
            result_code=$?
            [[ $result_code -ne 0 ]] && echo "[make FAILURE]" && exit $result_code;
                        
            rm -rf /usr/pgsql/lib/*.so.*
            rm -rf /usr/pgsql/lib/*.so
            return 0 

            '
            )
            ->withPkgName('libpq')
            ->withPkgConfig('/usr/pgsql/lib/pkgconfig')
            ->withLdflags('-L/usr/pgsql/lib/')
            ->withBinPath('/usr/pgsql/bin/')
    );
}

静态编译libffi

function install_libffi($p)
{
    $p->addLibrary(
        (new Library('libffi'))
            ->withHomePage('https://sourceware.org/libffi/')
            ->withLicense('http://github.com/libffi/libffi/blob/master/LICENSE', Library::LICENSE_BSD)
            ->withUrl('https://github.com/libffi/libffi/releases/download/v3.4.4/libffi-3.4.4.tar.gz')
            ->withFile('libffi-3.4.4.tar.gz')
            ->withPrefix('/usr/libffi/')
            ->withScriptBeforeConfigure(
                'test -d /usr/libffi && rm -rf /usr/libffi'
            )
            ->withConfigure(
                '
            ./configure --help ;
            ./configure \
            --prefix=/usr/libffi \
            --enable-shared=no \
            --enable-static=yes 
            '
            )
            ->withPkgName('libffi')
            ->withPkgConfig('/usr/libffi/lib/pkgconfig')
            ->withLdflags('-L/usr/libffi/lib/')
            ->withBinPath('/usr/libffi/bin/')
    //->withSkipInstall()
    //->disablePkgName()
    //->disableDefaultPkgConfig()
    //->disableDefaultLdflags()
    );
}

提示: 构建依赖库解决依赖的3种办法

办法一: 直接指定依赖库所在目录 。例如(--with-openssl=/usr/openssl)

办法二: 使用 pkg-config

办法三: 上述两种办法混用,大部分情况是(办法一)比(办法二)优先级高

为啥会混用,因为一部分库未提供 pkg-config 配置。 比如bzip2 ,iconv ,libgif

例子:构建 curl

            package_name='zlib openssl libcares libbrotlicommon libbrotlidec libbrotlienc libzstd libnghttp2 libidn2'
            CPPFLAGS="$(pkg-config  --cflags-only-I  --static $package_name)" \
            LDFLAGS="$(pkg-config   --libs-only-L    --static $package_name)" \
            LIBS="$(pkg-config      --libs-only-l    --static $package_name)" \
            ./configure --prefix=/usr/curl  \
            --enable-static \
            --disable-shared \
            --without-librtmp \
            --disable-ldap \
            --disable-rtsp \
            --enable-http \
            --enable-alt-svc \
            --enable-hsts \
            --enable-http-auth \
            --enable-mime \
            --enable-cookies \
            --enable-doh \
            --enable-threaded-resolver \
            --enable-ipv6 \
            --enable-proxy  \
            --enable-websockets \
            --enable-get-easy-options \
            --enable-file \
            --enable-mqtt \
            --enable-unix-sockets  \
            --enable-progress-meter \
            --enable-optimize \
            --with-zlib=/usr/zlib \
            --with-openssl=/usr/openssl \
            --enable-ares=/usr/cares \
            --with-default-ssl-backend=openssl \
            --with-libidn2 \
            --with-nghttp2 \
            --without-ngtcp2 \
            --without-nghttp3 

openssl 证书路径

macOS 下会指向 ~/.swoole_cli/openssl/ssl ,linux 会指向 /usr/openssl/ssl

用户需要创建软连接,可在编译 openssl 时指定证书路径,直接使用操作系统的证书

请问为什么xlswriter被删除了?

@jingjingxyk 请问为什么xlswriter被删除了?您一般使用什么方案来解决xls读写文件的?我们之前使用 PHPExcel ,但是速度慢,所以就换了。您下线掉 xlswriter 是因为有更好的选择吗?

TODO: 使用 Github Action 自动构建,并自动上传到平台

使用 Github Action 自动构建,并上传发布:

发布

  • Github swoole-src releases
  • Gitee swoole-src releases
  • Github swoole-clireleases
  • Gitee swoole-cli releases
  • 腾讯云 OSSswoole.com/download 页面)

平台

  • Linux x86-64
  • Linux arm64
  • macOS x86-64
  • macOS arm64
  • Windows x86-64 cygwin

使用依赖库镜像地址

使用依赖库镜像地址

方式一:

php prepare.php   +ds +inotify +apcu +protobuf --with-download-mirror-url=https://swoole-cli.jingjingxyk.com

方式二:

执行这个脚本, 原理: 自动下载 https://swoole-cli.jingjingxyk.com/all-archive.zip

sh sapi/download-box/download-box-get-archive-from-server.sh

方式三:

借助容器分发

sh sapi/download-box/download-box-get-archive-from-container.sh
# 容器分发原理介绍
container_id=$(docker create $IMAGE) # returns container ID
docker cp $container_id:/usr/share/nginx/html/extensions extensions
docker cp $container_id:/usr/share/nginx/html/libraries libraries
docker rm $container_id

构建依赖库镜像参考: https://github.com/swoole/swoole-cli/tree/main/sapi/download-box

configure:31121: error: Unable to locate gmp.h

version: v5.0.1 / current main

command:
./make.sh config

configure:27873: $? = 0
configure:30163: checking for GNU gettext support
configure:30200: result: no
configure:30892: checking for GNU MP support
configure:30929: result: yes
configure:31121: error: Unable to locate gmp.h

cygwin64 编译本项目时,需要删除 main/main.c 文件中的2行代码,才能链接通过,不知道怎么解决这个问题

链接阶段找不到 结构体 zend_extension_entry

main/main.c 需要删除的行是: 2263,2264 行

	/* start Zend extensions */
	extern zend_extension ;
	# zend_register_extension(&zend_extension_entry, NULL);
	# zend_startup_extensions();

错误信息:

image

删除两行代码以后,可以编译通过

test -f main/main.c.backup ||  sed -i.backup '2263,2264d' main/main.c

截图 2023-02-13 18-57-41

web ui 助力按需编译

web ui (雏形 暂只启用前端页面页面) : https://swoole-cli-ui.jingjingxyk.com/

缘由: swoole/swoole-src#4636

视频: https://www.bilibili.com/video/BV1Eb4y1n7xE/
视频节点: 0:58:34
视频节点: 1:02:44
视频节点: 1:05:34

swoole-cli 实验分支 experiment
借助 swoole-cli 项目提供的依赖库,编译器PHP其他版本 ,使用这个分支 build_native_php

其他:
借助依赖库 micro 二进制版本 build_native_php_sfx_micro
php-7.3.33
php-7.4.33

完整步骤:

bash sapi/quickstart/setup-php-runtime.sh --mirror china

bash sapi/quickstart/linux/run-alpine-3.16-container-full.sh

# 进入容器
bash sapi/quickstart/linux/connection-swoole-cli-alpine.sh


sh sapi/quickstart/linux/alpine-3.16-init.sh --mirror china

composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/

composer update --no-dev  --optimize-autoloader

php prepare.php --with-global-prefix=/usr --with-download-mirror-url=https://swoole-cli.jingjingxyk.com/ +protobuf

# bash make.sh all-library  (这步省略,因为已经通过容器技术提前构建好依赖库,并打包到容器中,运行容器已经包含依赖库)
bash make.sh config
bash make.sh build

bash make.sh archive

借助本项目构建的依赖库,编译PHP其他版本--例子PHP7.4 ,PHP 8.20

比如:php 7.4 、 php 8.20

第一步:运行已经构建好依赖库的容器:

这两个容器镜像都是一样的,区别是:容器镜像的生成过程不同
前者通过 docker commit 生成
后者通过 Dockerfile 分步构建生成

#!/bin/env sh 
__DIR__=$(
  cd "$(dirname "$0")"
  pwd
)

image=phpswoole/swoole-cli-builder:1.6

image=registry.cn-beijing.aliyuncs.com/jingjingxyk-public/app:build-swoole-cli-build-dependencies-alpine-edge-20230226T074232Z


docker run --rm --name  swoole-cli-build-dev-all-dependencies-container -d -v ${__DIR__}:/work -w /work $image tail -f /dev/null

第二步:静态编译PHP

这三个分支,选择自己需要的,他们之间变化并不大哈。自己修改PHP 版本就行
build_native_php
build_php_8.2
build_php_7.4
build_php_7.3 需要更换为GCC 、glibc

步骤也没变

php prepare.php  
sh make.sh all_library
sh make.sh php_src   # 这一步执行下载PHP 源码,并把需要的扩展的源码拷贝到 PHP源码目录
sh amke.sh config 
sh make.sh build 
sh make.sh archive

brotli编译链接时出现找不到函数,解决办法

通过查阅文档和反复实践,确认了原因和解决办法
原因所在:

 'mv ' . BROTLI_PREFIX . '/lib/libbrotlicommon-static.a ' . BROTLI_PREFIX . '/lib/libbrotli.a',

image

解决办法:

'cp ' . BROTLI_PREFIX . '/lib/libbrotlicommon-static.a ' . BROTLI_PREFIX . '/lib/libbrotli.a',
'mv ' . BROTLI_PREFIX . '/lib/libbrotlicommon-static.a ' . BROTLI_PREFIX . '/lib/libbrotlicommon.a',

image

最终解决:#36

image

@matyhtf

swoole-cli windows 版,如何解决 /cygdrive/c/ 路径不存在问题,是不是必须安装cygwin 环境?

配置系统变量PATH 以后,是可以使用的

# 设置软连接

mklink  "C:\Users\biubiu\Downloads\swoole-cli-v5.0.1-cygwin64\bin\php.exe"  "C:\Users\biubiu\Downloads\swoole-cli-v5.0.1-cygwin64\bin\swoole-cli.exe" 

swoole-cli -v
php -v

get_dir.php

<?php

echo __DIR__;
php get_dir.php

但是当使用魔术变量 __DIR__ 时,返回的路径不存在

image

操作系统是不是还必须安装 cygwin

安装cygwin

setup-x86_64.exe -B -O -s http://cygwin.mirror.constant.com

cygwin 是否有版本要求?

cygwin 编译预览--编译swoole-cli一次 耗时 30分钟左右

缘由: 反复尝试 github action windows-latest 环境,发现编译始终不通过

解决办法: 用一台全新的服务器来编译测试 ,找到问题所在。

阿里云按量付费服务器 4核16G windows 2022 数据中心版 服务器成本:3元RMB左右

安装 cygwin setup-x86_64.exe依赖,花费半小时左右 (有情提醒: 提前准备好安装包等,可以节省时间)

提前准备脚本如下: (备注 ^ 是windows cmd 换行符)

setup-x86_64.exe  --no-desktop --no-shortcuts --no-startmenu --quiet-mode    -s https://mirrors.ustc.edu.cn/cygwin/  -P git,curl,wget,tar,libtool,re2c,bison,gcc-g++,autoconf,automake,openssl,libpcre2-devel,libssl-devel,libcurl-devel,libxml2-devel,libxslt-devel,libgmp-devel,ImageMagick,libpng-devel,libjpeg-devel,libfreetype-devel,libwebp-devel,libsqlite3-devel,zlib-devel,libbz2-devel,liblz4-devel,liblzma-devel,libzip-devel,libicu-devel,libonig-devel,libcares-devel,libsodium-devel,libyaml-devel,libMagick-devel,libzstd-devel,libbrotli-devel,libreadline-devel,libintl-devel,libpq-devel,libssh2-devel,libidn2-devel,gettext-devel,coreutils


发现问题所在: 因github runner 已经内置了msys 环境, cygwin 如果不安装 make ,默认引用的是 mingw-make。需要cygwin 安装 make 解决问题 。另外还有需要创建目录 mkdir -p bin/.libs

image
mkdir -p bin/.libs

image
image

解决macos curl configure 检测不通过 参考

文档 doc-macos.md

## curl configure 检测不通过
修改 `ext/curl/config.m4` ,去掉 `HAVE_CURL` 检测

依据上述文档的提示:写如下功能

function install_php_internal_extension_curl_patch(Preprocessor $p)
{
    $workDir=$p->getWorkDir();
    $command = '';

    if(is_file("{$workDir}/ext/curl/config.m4.backup")){
        $originFileHash=md5(file_get_contents("{$workDir}/ext/curl/config.m4"));
        $backupFileHash=md5(file_get_contents("{$workDir}/ext/curl/config.m4.backup"));
        if($originFileHash == $backupFileHash){
            $command =<<<EOF
           test -f {$workDir}/ext/curl/config.m4.backup && rm -f {$workDir}/ext/curl/config.m4.backup
           test -f {$workDir}/ext/curl/config.m4.backup ||  sed -i.backup '75,82d' {$workDir}/ext/curl/config.m4
EOF;
        }
    } else {
        $command =<<<EOF
           test -f {$workDir}/ext/curl/config.m4.backup ||  sed -i.backup '75,82d' {$workDir}/ext/curl/config.m4
EOF;
    }

    $p->addLibrary(
    (new Library('patch_php_internal_extension_curl'))
        ->withHomePage('https://www.php.net/')
        ->withLicense('https://github.com/php/php-src/blob/master/LICENSE', Library::LICENSE_PHP)
        ->withUrl('https://github.com/php/php-src/archive/refs/tags/php-8.1.12.tar.gz')
        ->withManual('https://www.php.net/docs.php')
        ->withLabel('php_extension_patch')
        ->withScriptBeforeConfigure($command)
        ->withConfigure('return 0 ')
        ->disableDefaultPkgConfig()
        ->disableDefaultLdflags()
        ->disablePkgName()
    );
}

macos 下避开被 /usr 目录替换

if ($p->getOsType() == 'macos') {
    $p->addEndCallback(function () use ($p) {
        $header=<<<'EOF'
export PATH=/opt/homebrew/bin/:/usr/local/bin/:$PATH
EOF;
        $command= file_get_contents(__DIR__ . '/make.sh');
        $command=$header.PHP_EOL.$command;
        file_put_contents(__DIR__ . '/make.sh',$command);
    });

}

$p->addEndCallback(function () use ($p) {
    $header=<<<'EOF'
#!/bin/env sh
set -uex
PKG_CONFIG_PATH='/usr/lib/pkgconfig'
test -d /usr/lib64/pkgconfig && PKG_CONFIG_PATH="/usr/lib64/pkgconfig:$PKG_CONFIG_PATH" ;
test -d /usr/local/lib64/pkgconfig && PKG_CONFIG_PATH="/usr/local/lib64/pkgconfig:$PKG_CONFIG_PATH" ;

cpu_nums=`nproc 2> /dev/null || sysctl -n hw.ncpu`
# `grep "processor" /proc/cpuinfo | sort -u | wc -l`

EOF;
    $command= file_get_contents(__DIR__ . '/make.sh');
    $command=$header.PHP_EOL.$command;
    file_put_contents(__DIR__ . '/make.sh',$command);
});

image

image

image

下载依赖库 使用镜像地址

php prepare.php \
--with-build-type=dev \
--with-dependency-graph=1 \
+apcu +ds +inotify \
--without-docker=1 \
--with-download-mirror-url=https://swoole-cli.jingjingxyk.com/

Enable c-ares support, require c-ares library

按照make.sh中的指令进行安装完成

cd /work/thirdparty
    echo "build cares"
    mkdir -p /work/thirdparty/cares && \
    tar --strip-components=1 -C /work/thirdparty/cares -xf /work/pool/lib/c-ares-1.18.1.tar.gz  && \
    cd cares && \
    echo  "./configure --prefix=/usr --enable-static --disable-shared"
        ./configure --prefix=/usr --enable-static --disable-shared && \
        make -j 8   && \
    make install
    cd -

安装完成

list.3 ares_strerror.3 ares_timeout.3 ares_version.3 '/usr/share/man/man3'
make[2]: Leaving directory '/work/c-ares-1.18.1/docs'
make[1]: Leaving directory '/work/c-ares-1.18.1/docs'
Making install in test
make[1]: Entering directory '/work/c-ares-1.18.1/test'
make[2]: Entering directory '/work/c-ares-1.18.1/test'
make[2]: Nothing to be done for 'install-exec-am'.
make[2]: Nothing to be done for 'install-data-am'.
make[2]: Leaving directory '/work/c-ares-1.18.1/test'
make[1]: Leaving directory '/work/c-ares-1.18.1/test'
make[1]: Entering directory '/work/c-ares-1.18.1'
make[2]: Entering directory '/work/c-ares-1.18.1'
make[2]: Nothing to be done for 'install-exec-am'.
 ./install-sh -c -d '/usr/lib/pkgconfig'
 /usr/bin/install -c -m 644 libcares.pc '/usr/lib/pkgconfig'
make[2]: Leaving directory '/work/c-ares-1.18.1'
make[1]: Leaving directory '/work/c-ares-1.18.1'

执行make.sh build报以下异常

/work/swoole-cli/ext/swoole/ext-src/php_swoole_private.h:85:2: error: "Enable c-ares support, require c-ares library"
#error "Enable c-ares support, require c-ares library"
 ^
In file included from /work/swoole-cli/ext/swoole/ext-src/php_swoole_cxx.cc:1:
In file included from /work/swoole-cli/ext/swoole/ext-src/php_swoole_cxx.h:19:
/work/swoole-cli/ext/swoole/ext-src/php_swoole_private.h:85:2: error: "Enable c-ares support, require c-ares library"
#error "Enable c-ares support, require c-ares library"
 ^
/work/swoole-cli/ext/swoole/ext-src/php_swoole.cc:55:10: fatal error: 'ares.h' file not found
#include <ares.h>
         ^~~~~~~~
In file included from /work/swoole-cli/ext/swoole/ext-src/swoole_admin_server.cc:17:
In file included from /work/swoole-cli/ext/swoole/ext-src/php_swoole_server.h:21:
In file included from /work/swoole-cli/ext/swoole/ext-src/php_swoole_cxx.h:19:
/work/swoole-cli/ext/swoole/ext-src/php_swoole_private.h:85:2: error: "Enable c-ares support, require c-ares library"
#error "Enable c-ares support, require c-ares library"
 ^
2 errors generated.
make: *** [Makefile:1898: ext/swoole/ext-src/php_swoole.lo] Error 1
make: *** Waiting for unfinished jobs....
In file included from /work/swoole-cli/ext/swoole/ext-src/swoole_async_coro.cc:17:
In file included from /work/swoole-cli/ext/swoole/ext-src/php_swoole_cxx.h:19:
/work/swoole-cli/ext/swoole/ext-src/php_swoole_private.h:85:2: error: "Enable c-ares support, require c-ares library"
#error "Enable c-ares support, require c-ares library"
 ^
In file included from /work/swoole-cli/ext/swoole/ext-src/swoole_atomic.cc:17:
/work/swoole-cli/ext/swoole/ext-src/php_swoole_private.h:85:2: error: "Enable c-ares support, require c-ares library"
#error "Enable c-ares support, require c-ares library"
 ^
In file included from /work/swoole-cli/ext/swoole/ext-src/swoole_channel_coro.cc:20:
In file included from /work/swoole-cli/ext/swoole/ext-src/php_swoole_cxx.h:19:
/work/swoole-cli/ext/swoole/ext-src/php_swoole_private.h:85:2: error: "Enable c-ares support, require c-ares library"
#error "Enable c-ares support, require c-ares library"
 ^
1 error generated.
make: *** [Makefile:1910: ext/swoole/ext-src/swoole_atomic.lo] Error 1
1 error generated.
make: *** [Makefile:1901: ext/swoole/ext-src/php_swoole_cxx.lo] Error 1
In file included from /work/swoole-cli/ext/swoole/ext-src/swoole_client_coro.cc:17:
In file included from /work/swoole-cli/ext/swoole/ext-src/php_swoole_cxx.h:19:
/work/swoole-cli/ext/swoole/ext-src/php_swoole_private.h:85:2: error: "Enable c-ares support, require c-ares library"
#error "Enable c-ares support, require c-ares library"
 ^
In file included from /work/swoole-cli/ext/swoole/ext-src/swoole_client.cc:17:
In file included from /work/swoole-cli/ext/swoole/ext-src/php_swoole_cxx.h:19:
/work/swoole-cli/ext/swoole/ext-src/php_swoole_private.h:85:2: error: "Enable c-ares support, require c-ares library"
#error "Enable c-ares support, require c-ares library"

curl 启用nghttp2时出现 multiple definition of `nghttp2_strerror'; 函数多重定义

multiple definition of `nghttp2_strerror'; 函数多重定义

与这里出现冲突 https://github.com/swoole/swoole-src/blob/master/thirdparty/nghttp2/nghttp2_helper.c

/usr/bin/ld: /usr/nghttp2/lib/libnghttp2.a(nghttp2_helper.o): in function `nghttp2_strerror':
/work/thirdparty/nghttp2/lib/nghttp2_helper.c:254: multiple definition of `nghttp2_strerror'; ext/swoole/thirdparty/nghttp2/nghttp2_helper.o:/work/ext/swoole/thirdparty/nghttp2/nghttp2_helper.c:35: first defined here
clang-15: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [Makefile:295: bin/swoole-cli] Error 1

image

扩展依赖库 关系图

鼠标右键新标签页打开图片 图片上的链接是可以点击的,点击自动跳转到指定代码仓库
生成命令

php prepare.php --with-build-type=dev --with-dependency-graph=1 +ds +apcu +protobuf 生成graphvi z 模板文件
sh sapi/scripts/generate-dependency-graph.sh 生成svg 和 pdf

ext-dependency-graph

每天都在关注,提一个想法

一直在关注cli的更新情况,希望可以支持把hyperf框架打包的phar包直接编译进cli,这样分发出去只要给一个文件就够了

为了能直观的看到依赖关系,这个版本没有跟随主仓库,把构建安装依赖库的过程放到conf.d目录

主仓库依赖库安装顺序 查看

# 查看依赖库和依赖库安装顺序
 ./make.sh list-library 

# 查看各库 pkg-config 配置信息
./make.sh pkg-check

有兴趣的同志可以看参考以下:https://github.com/jingjingxyk/swoole-cli/pull/31/files

各依赖库构建过程放到:library_install_builder.php文件

库或者扩展的依赖关系简述: 用注释写在这个文件里library_builder.php

该版本与主仓库版本的差异

因为不能直观的看到依赖关系,因此诞生这个版本

image

image
image
image
image

macOS 连接阶段抛出 warning

clang: warning: argument unused during compilation: '-fno-ident' [-Wunused-command-line-argument]
clang: warning: argument unused during compilation: '-all-static' [-Wunused-command-line-argument]
clang: warning: argument unused during compilation: '-fno-ident' [-Wunused-command-line-argument]

这些参数是无效的

使用 curl 代替 wget 下载软件,支持 socks5 代理

由于 wget 仅支持 http 代理,不支持 socks5 代理,导致无法使用代理。需要替换为 curl,curl 同时支持两种代理方式。

export http_proxy=socks5h://127.0.0.1:1080
export https_proxy=socks5h://127.0.0.1:1080

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.