PHP Extension written with C++. Build and check with GitHub Actions.
Tags: actionshackathon21
Published: 2021-11-10 20:27:45

##### My Workflow
Small description about repository: [phptdlib](https://github.com/yaroslavche/phptdlib) is a PHP extension for the [Telegram Database library](https://core.telegram.org/tdlib), which allows to create Telegram clients. This is a CMake based C++ project with dependencies ([tdlib/td](https://github.com/td/tdlib), [CopernicaMarketingSoftware/PHP-CPP](https://github.com/CopernicaMarketingSoftware/PHP-CPP) and [nlohmann/json](https://github.com/nlohmann/json)), which produces a PHP extension.

First of all, need to prepare environment for building CMake project
```yaml
jobs:
    build:
        name: ${{ matrix.config.name }}
        runs-on: ${{ matrix.config.os }}
        env: # custom ENV variables
            CONFIG: gcc
            CC: gcc
            CXX: g++
        strategy:
            fail-fast: false
            matrix:
                config:
                    - {
                        name: "Ubuntu Latest GCC (Release)",
                        os: ubuntu-latest,
                        build_type: "Release",
                        cc: "gcc",
                        cxx: "g++",
                        generators: "Ninja"
                    }
```
And in steps right after repo checkout need to add PHP headers and capability for running PHP code. Thanks to [shivammathur/setup-php@v2](https://github.com/shivammathur/setup-php) it's pretty easy to achieve:

```yaml
        steps:
            -   uses: actions/checkout@v2
            -   name: Setup PHP 7.4 with PECL extension
                uses: shivammathur/setup-php@v2
                with:
                    php-version: '7.4'
```

After that we're ready to install development tools and check their versions:
```yaml
            -   name: Install main dependencies (Ubuntu)
                if: startsWith(matrix.config.name, 'Ubuntu Latest GCC')
                run: |
                    sudo apt-get update
                    sudo apt-get install ninja-build cmake gperf build-essential zlib1g-dev
                    ninja --version
                    cmake --version
                    gcc --version
                    php --version
```
Here you can note that we're able to extend the matrix and configure for each environment its own workflow.


In the build process there is one huge disadvantage - it takes a lot of resources and plenty of time. It's bad to occupy resources, when they aren't needed. That's why it's worth it to cache compiled object files.
```yaml
            -   name: Cache extension dependencies
                id: cahce-ext-deps
                uses: actions/cache@v2
                with:
                    path: ~/cached_builds
                    key: ${{ runner.os }}-ext-deps
```
But, honestly, I think this config isn't really correctly configured for my case. The idea was in caching compiled object files and later just use that directory and linker would use that object files (in the install script from the next step). But looks like it doesn't work as I've expected and the compiler compiles object files even when no changes are made in dependencies. I'll be very appreciated for an advice.

I've created an [install script](https://github.com/yaroslavche/phptdlib/blob/master/scripts/install.sh) for updating dependencies for shared lib builds. It takes the build path as the first argument, pulls the latest code from `tdlib/td`, `CopernicaMarketingSoftware/PHP-CPP` and `nlohmann/json` repositories and builds separately as shared libraries.
```yaml
            -   name: Install extension dependencies
                shell: bash
                run: |
                    ./scripts/install.sh ~/cached_builds
                    cd ~/cached_builds
                    sudo ldconfig
```
This process takes around 10 minutes.

When dependencies are built and installed, we're ready to install extension itself:
```yaml
            -   name: Build and install
                shell: bash
                run: |
                    mkdir build
                    cd build
                    cmake -D USE_SHARED_TD:BOOL=ON -D USE_SHARED_JSON:BOOL=ON -D USE_SHARED_PHPCPP:BOOL=ON ..
                    make
                    sudo make install
```

And if all above steps are fine, then we can check if it is installed and works. Need to check installed modules and try to run example scripts.
```yaml
            -   name: Test
                shell: bash
                run: |
                    pwd
                    php -m | grep tdlib
                    php php_examples/func.php
```

And need to specify when it is needed to trigger actions. In my case I also want to configure scheduled runs more often (twice in a month) because build fails would notify me that need to update dependencies.
```yaml
on:
    push:
    pull_request:
    release:
    schedule:
        -   cron: "0 0 1,15 * *"
```

Before I used travis, but it accidentally stopped working for me at some point, and I've decided to migrate to GitHub Actions. Right now it's not ideal and uses just one config and one entry in the matrix, but it's doing its job and can be configured better in future.
Thanks for reading =)

##### Submission Category: 
Wacky Wildcards


##### Yaml File or Link to Code
{% github https://github.com/yaroslavche/phptdlib %}