This tutorial will show how to author your own CDep package and host it on Github. We'll package BoringSSL so that it can be used by CDep. When you're done you'll have a package that any CDep user can reference in their project.
Prerequisites: Have or create a Github account and read Anatomy of a CDep Package
This tutorial runs on Ubuntu and it will require some modifications to work on MacOS or Windows.
Navigate to https://github.com/google/boringssl and click the Fork button. After the fork is complete, go to settings and rename the repository to "boringssl-tutorial". Now clone your "boringssl-tutorial" repository onto your local machine.
This step installs CMake into your "boringssl-tutorial" folder. You can skip this step if you already have CMake 3.7.1 or later, but you will need to modifiy subsequent steps to reference that CMake instead. If you are not using Linux go to the CMake downloads page to get the zip file URL for your OS.
cd boringssl-tutorial
wget https://cmake.org/files/v3.8/cmake-3.8.1-Linux-x86_64.tar.gz
tar xvzf cmake-3.8.1-Linux-x86_64.tar.gz
This step installs a recent Android NDK. This has the libraries and compilers needed to target Android with C++.
Note: The latest NDK downloads are available on the NDK website.
wget https://dl.google.com/android/repository/android-ndk-r14b-linux-x86_64.zip
unzip android-ndk-r14b-linux-x86_64.zip
This step builds BoringSSL for armeabi. You can repeat this step for other ABIs, but that's not necessary for this tutorial.
cmake-3.8.1-Linux-x86_64/bin/cmake \
-H. \
-Bbuild/armeabi \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_ANDROID_NDK_TOOLCHAIN_VERSION=clang \
-DCMAKE_SYSTEM_NAME=Android \
-DCMAKE_SYSTEM_VERSION=16 \
-DCMAKE_ANDROID_STL_TYPE=c++_static \
-DCMAKE_ANDROID_NDK=`pwd`/android-ndk-r14b \
-DCMAKE_ANDROID_ARCH_ABI=armeabi
cmake-3.8.1-Linux-x86_64/bin/cmake --build build/armeabi
At this point CMake should have built a couple of static libraries.
build/armeabi/ssl/libssl.a
build/armeabi/crypto/libcrypto.a
If these files aren't there then something went wrong in the steps above.
A few notes while we're here.
-
CDep packages currently only support static libraries (.a files). For an app, you will need a shared library (.so file), but shipping a static library allows the user to decide whether to statically or dynamically link to BoringSSL. This also saves complexity in the CDep tool and reduces the size of package.
-
As a best practice, it is recommended that the libraries in the archive be optimized and have symbols (CMAKE_BUILD_TYPE=RelWithDebInfo). The Android gradle plugin will strip symbols so they don't end up in the APK.
The staging folder holds the library files in a convenient form for zipping.
mkdir -p staging/lib/armeabi
cp build/armeabi/ssl/libssl.a staging/lib/armeabi
cp build/armeabi/crypto/libcrypto.a staging/lib/armeabi
The upload folder contains the files we will eventually upload to Github as a Release.
mkdir upload
pushd staging
zip -r ../upload/boringssl-tutorial-armeabi.zip .
popd
NB: If your package has generated headers that are specific to the abi, then the process here needs to follow this simple modification.
mkdir upload
cp -Rp build/gen/armeabi/include staging/include
pushd staging
zip -r ../upload/boringssl-tutorial-armeabi.zip .
popd
zip -r upload/boringssl-tutorial-headers.zip include/
NB: In the event your package contains generated headers then they will need to be added during step 6. The include files that go here are for includes that are common across all abi types.
This creates a file called cdep-manifest.yml that describes the package. You can also do this step in a text editor if you like.
Note that yourname below should be replaced by your Github user name. Also note that artifactId must match the name of the Github repo from the fork in Step 1. If it doesn't CDep won't be able to locate it later.
printf "%s\r\n" "coordinate:" > upload/cdep-manifest.yml
printf " %s\r\n" "groupId: com.github.*yourname*" >> upload/cdep-manifest.yml
printf " %s\r\n" "artifactId: boringssl-tutorial" >> upload/cdep-manifest.yml
printf " %s\r\n" "version: 0.0.0" >> upload/cdep-manifest.yml
BoringSSL doesn't have version numbers so we just use '0.0.0' as a starting version.
As a best practice it is strongly recommended that once you publish a package with a particular version you don't change it. In this tutorial publishing happens in step 15.
There are a few reasons packages should be immutable once they're published.
- Most importantly, if you change a package after it is published then you can break user's build that depend on it.
- CDep won't try to redownload the package if it already has a package with that name and version in the cache.
- CDep stores the sha256 hash of the manifest and will refuse to use the package if the manifest has changed.
A CDep license section can have a 'name' or a 'url' or both. BoringSSL has a rather complicated license that is difficult to name so in this case we'll just use url to the LICENSE file in the original project.
printf "%s\r\n" "license:" >> upload/cdep-manifest.yml
printf " %s\r\n" "url: https://raw.githubusercontent.com/google/boringssl/master/LICENSE" \
>> upload/cdep-manifest.yml
This step adds information to the manifest about the header files archive.
printf "%s\r\n" "interfaces:" >> upload/cdep-manifest.yml
printf " %s\r\n" "headers:" >> upload/cdep-manifest.yml
printf " %s\r\n" "file: boringssl-tutorial-headers.zip" >> upload/cdep-manifest.yml
printf " %s\r\n" "include: include" >> upload/cdep-manifest.yml
printf " sha256: " >> upload/cdep-manifest.yml
At this point, we need to compute the sha256 of the header zip and add it to the manifest.
shasum -a 256 upload/boringssl-tutorial-headers.zip | awk '{print $1}' >> upload/cdep-manifest.yml
Last, we need add the size of the zip file to the manifest.
printf " size: " >> upload/cdep-manifest.yml
ls -l upload/boringssl-tutorial-headers.zip | awk '{print $5}' >> upload/cdep-manifest.yml
This step is similar to step 10. It adds the zipped libraries archive along with size and sha256.
printf "%s\r\n" "android:" >> upload/cdep-manifest.yml
printf " %s\r\n" "archives:" >> upload/cdep-manifest.yml
printf " %s\r\n" "- file: boringssl-tutorial-armeabi.zip" >> upload/cdep-manifest.yml
printf " sha256: " >> upload/cdep-manifest.yml
shasum -a 256 upload/boringssl-tutorial-armeabi.zip | awk '{print $1}' >> upload/cdep-manifest.yml
printf " size: " >> upload/cdep-manifest.yml
ls -l upload/boringssl-tutorial-armeabi.zip | awk '{print $5}' >> upload/cdep-manifest.yml
Specify the ABI that the libraries target.
printf " %s\r\n" " abi: armeabi" >> upload/cdep-manifest.yml
Specify the Android platform that the libraries are built for.
printf " %s\r\n" " platform: 16" >> upload/cdep-manifest.yml
Specify the libraries that the archive holds. Ensure that the order is correct as the linker will maintain it for the link line. The linker will read from left to right noting missing objects as it goes. The library that needs symbols must be on the left. In this case, libssl.a depends upon objects in libcrypto.a so the line below is proper.
printf " libs: [libssl.a, libcrypto.a]\r\n" >> upload/cdep-manifest.yml
NB: If your project has generated headers that are abi specific. Add the path to them here:
printf " include: include\r\n"
CDep requires the manifest contain a small example of how to use the library. This is so that tools and the end-user can prove that the library links using only information contained in the package.
printf "%s\r\n" "example: |" >> upload/cdep-manifest.yml
printf "%s\r\n" " #include <openssl/bio.h>" >> upload/cdep-manifest.yml
printf "%s\r\n" " #include <openssl/ssl.h>" >> upload/cdep-manifest.yml
printf "%s\r\n" " #include <openssl/err.h>" >> upload/cdep-manifest.yml
printf "%s\r\n" " void example() {" >> upload/cdep-manifest.yml
printf "%s\r\n" " SSL_load_error_strings();" >> upload/cdep-manifest.yml
printf "%s\r\n" " ERR_load_BIO_strings();" >> upload/cdep-manifest.yml
printf "%s\r\n" " OpenSSL_add_all_algorithms();" >> upload/cdep-manifest.yml
printf "%s\r\n" " }" >> upload/cdep-manifest.yml
At this point, there should be a valid CDep package in the upload folder. Use CDep to validate this.
First, install CDep in the current folder.
git clone https://github.com/jomof/cdep-redist.git
cdep-redist/cdep wrapper
Now use CDep to fetch the package from the upload folder.
./cdep fetch upload/cdep-manifest.yml
If the manifest is well formed then you should see a message like this.
Downloading boringssl-tutorial/upload/boringssl-tutorial-armeabi.zip
Fetch complete
Now we'll use the example code from step 12 to prove that the package can be built into a final .so. First, generate example projects.
printf "%s\r\n" "builders: [cmake, cmakeExamples, ndk-build]" > cdep.yml
printf "%s\r\n" "dependencies:" >> cdep.yml
printf "%s\r\n" "- compile: upload/cdep-manifest.yml" >> cdep.yml
./cdep
If that worked you should see a message like this.
Generating .cdep/modules/cdep-dependencies-config.cmake
Generating .cdep/examples/cmake/com.github.jomof/boringssl-tutorial/0.0.0/boringssl-tutorial.cpp
Generating .cdep/examples/cmake/com.github.jomof/boringssl-tutorial/0.0.0/CMakeLists.txt
Generating .cdep/examples/cmake/CMakeLists.txt
Generating .cdep/modules/ndk-build/cdep-dependencies/Android.mk
Now build the example project.
cmake-3.8.1-Linux-x86_64/bin/cmake \
-H.cdep/examples/cmake/ \
-Bbuild/examples \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_ANDROID_NDK_TOOLCHAIN_VERSION=clang \
-DCMAKE_SYSTEM_NAME=Android \
-DCMAKE_SYSTEM_VERSION=16 \
-DCMAKE_ANDROID_STL_TYPE=c++_static \
-DCMAKE_ANDROID_NDK=`pwd`/android-ndk-r14b \
-DCMAKE_ANDROID_ARCH_ABI=armeabi
cmake-3.8.1-Linux-x86_64/bin/cmake --build build/examples
NB: To compile on OSX, use the cmake that comes with the Android SDK like this:
$ANDROID_HOME/cmake/3.6.3155560/bin/cmake \
-H.cdep/examples/cmake/ \
-Bbuild/examples \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_ANDROID_NDK_TOOLCHAIN_VERSION=clang \
-DCMAKE_SYSTEM_NAME=Android \
-DCMAKE_SYSTEM_VERSION=16 \
-DANDROID_PLATFORM=android-21 \
-DANDROID_ABI=armeabi \
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \
-DCMAKE_ANDROID_STL_TYPE=c++_static \
-DCMAKE_ANDROID_ARCH_ABI=armeabi
$ANDROID_HOME/cmake/3.6.3155560/bin/cmake --build build/examples
If that builds successfully then you can be pretty confident you have a working package.
Now, let's release it on Github so other people can use it.
Go to https://github.com/*yourname*/boringssl-tutorial/releases and press 'Create new release'. Tag the release as '0.0.0'. This has to match the version from Step 8.
This token is required to upload files from the local filesystem to Github. Go to https://github.com/settings/tokens and press 'Generate new token'. Name the token something like 'BoringSSL Tutorial'. Click the 'public_repo' checkbox. Then 'Generate token'.
IMPORTANT: Keep this token a secret. If someone has it then they can alter your projects on Github.
Press the 'Copy Token' button to copy the token to the clipboard.
Now, go back to the bash command-prompt and set an environment variable.
export GITHUB_TOKEN=<paste your token here>
Get a tool that will help us upload. Again, if you're not using Linux go to the releases page to choose the correct version for your OS.
wget https://github.com/aktau/github-release/releases/download/v0.7.2/linux-amd64-github-release.tar.bz2 -O linux-amd64-github-release.tar.bz2
tar xvjf linux-amd64-github-release.tar.bz2
Do the actual upload to Github.
bin/linux/amd64/github-release upload --user *yourname* --repo boringssl-tutorial --tag 0.0.0 \
--file upload/cdep-manifest.yml --name cdep-manifest.yml
bin/linux/amd64/github-release upload --user *yourname* --repo boringssl-tutorial --tag 0.0.0 \
--file upload/boringssl-tutorial-headers.zip --name boringssl-tutorial-headers.zip
bin/linux/amd64/github-release upload --user *yourname* --repo boringssl-tutorial --tag 0.0.0 \
--file upload/boringssl-tutorial-armeabi.zip --name boringssl-tutorial-armeabi.zip
At this point, assuming your Github repo is public, the package should be available to any CDep user. Let's prove this by fetching by coordinate.
./cdep fetch com.github.*yourname*:boringssl-tutorial:0.0.0
You should see something like this.
Downloading https://github.com/*yourname*/boringssl-tutorial/releases/download/0.0.0/cdep-manifest.yml
Fetch complete
At this point you have created and published a fully functioning CDep package.
Now would be a good time to delete the personal access token from step 15.