Linux VPS 上で Jenkins、Vivado、GitHub を使用して FPGA 開発を自動化する
* この記事には UpCloud VPS の広告リンクが含まれています
継続的デリバリーと継続的インテグレーションは、コードの変更とデプロイメントの間のサイクル タイムを短縮するアジャイル ソフトウェア開発手法です。自動化を使用してコードの変更を検証し、リリース ファイルをビルドすることで、チームの生産性と効率性を高めることができます。
ソフトウェア会社は長い間継続的開発を実践してきましたが、その方法を FPGA プロジェクトにも同様に使用できます。このチュートリアルでは、Jenkins、Xilinx Vivado、Git / GitHub ソース管理管理 (SCM) システムを使用して、仮想プライベート サーバー (VPS) 上にオートメーション サーバーをセットアップする方法を説明します。
ジェンキンスとは何ですか?
Jenkins オートメーション サーバーは、Java で書かれた無料のオープンソース プログラムです。 Windows または Linux 上で動作します。 Linux はヘッドレス サーバーの最も一般的なプラットフォームであるため、このブログ投稿では Linux を使用します。
Jenkins は、Linux ではデーモン プロセスとして、Windows ではサービスとして実行されます。 Jenkins の起動時に起動される組み込み Web サーバーがユーザー インターフェイスを提供します。ほとんどのユーザーは、Web インターフェイスを使用して Jenkins と対話します。 Web GUI を使用して、新しい自動化プロジェクトを追加したり、既存のプロジェクトを管理したりできます。
上の画像は、今日セットアップする Jenkins サーバーのメイン ページを示しています。デフォルトでは、ログインしたユーザーのみが Jenkins にアクセスできますが、この記事では、*デモ サーバーの一部へのパブリック アクセスを有効にしました。
* 更新:2020 年 5 月 13 日にデモ サーバーを停止しました
メインページに表示されるのはジョブのリストです。これらのジョブには任意のタスクを含めることができ、Web GUI から手動でトリガーできます。または、スクリプトや Webhook を通じて、または他のジョブの完了の結果として自動的にトリガーすることもできます。したがって、オートメーション サーバーという用語が使われます。 .
この例では、各ジョブは別の GitHub リポジトリに保存されている VHDL モジュールに対応します。開発者が監視対象の Git リポジトリの 1 つにコードをプッシュするたびに、Jenkins でシミュレーションを実行し、プロジェクトをビルドします。テストベンチが失敗した場合、またはビルドが中断した場合、Jenkins は Web インターフェイスでジョブを失敗としてマークし、欠陥のあるコードをコミットした人に電子メールを自動的に送信します。
サンプルプロジェクト
オートメーション サーバーは、大規模なプロジェクトに取り組んでいるチームに最も役立ちます。したがって、8 つの Git リポジトリで構成されるサンプル FPGA プロジェクトを構築しました。このプロジェクトは、Fast-Track コースの 7 セグメント ディスプレイ カウンターをザイリンクス ZedBoard に移植したものです。
GitHub 上の 8 つのリポジトリへのリンク:
- パッケージ (VHDL パッケージ)
- bcd_エンコーダ (モジュール)
- カウンター (モジュール)
- 数字セレクター (モジュール)
- 出力マルチプレクサ (モジュール)
- リセット (モジュール)
- seg7_エンコーダ (モジュール)
- セグ 7 (トップモジュール)
各リポジトリには、VHDL モジュールとそのテストベンチが含まれています。例外はパッケージです。 リポジトリには、定数と型を定義する 3 つの VHDL パッケージのみが含まれています。さらに、seg7 最上位モジュールには、物理実装のクロック速度とピン割り当てを定義する制約ファイルが含まれています。
大規模な VHDL プロジェクトのほとんどは、複数のリポジトリのモジュールを使用します。通常、企業は多くの設計で再利用するパッケージとモジュールのライブラリを持っています。これは、このかなり単純なデザインを多数のモジュールに分割することでエミュレートしているものです。
この例では、すべてのモジュールがパッケージ リポジトリに依存しており、トップ モジュールもすべてのサブモジュールに依存しています。標準の Git サブモジュールを使用して必要に応じてインポートすることで、この問題を解決しました。上のグラフは、このプロジェクト内のすべてのリポジトリのコンテンツと依存関係を示しています。
Git リポジトリには、Jenkins 構成やビルド スクリプトなど、設計以外のファイルもいくつか含まれています。それらについては、この記事の今後のセクションで説明します。
仮想プライベート サーバー (VPS)
Jenkins は任意の Windows または Linux コンピューター上で実行できますが、実際的な目的をすべて達成するには、専用サーバー上で実行することをお勧めします。オートメーション サーバーは常に稼働しており、チーム メンバー全員がアクセスできる必要があります。十分な容量を持つ物理サーバーがあれば、それは素晴らしいことです。しかし、ほとんどの人にとって、より早くて安価な解決策は、仮想プライベート サーバー (VPS) を使用することです。
VPS は、インターネット経由でホスティング会社からレンタルする仮想コンピューターです。これは実際の Windows または Linux コンピュータとして表示され、必要なソフトウェアを操作したりインストールしたりできます。 Linux コンピュータを使用するのは、それが私たちのユースケースにとって最も理にかなっているためです。
VHDLwhiz サイトは、過去 2 年間と同様に VPS 上で実行されています。私はすでに、最速かつ最高の VPS プロバイダーである UpCloud を見つけるのに苦労しました。当然のことながら、UpCloud を使用してオートメーション サーバーの VPS をセットアップします。
25 ドルの UpCloud ボーナスを獲得
UpCloud を試してみたい場合は、25 ドル相当のクレジットを提供する紹介コードを用意しています。
>> 25 ドルの UpCloud ボーナスを獲得するにはここをクリックしてください <<
または、チェックアウト時にプロモーション コード:NV78V6 を使用してください
コードを使用すると、ボーナスを獲得し、同時に VHDLwhiz をサポートできます。 UpCloud アカウントを使用するすべての顧客に対して、いくらかの資金が私の UpCloud アカウントに入金される可能性があります。
さて、セールストークはこれくらいにしておきます。サーバーのセットアップを始めましょう。
UpCloud VPS の導入
新しい UpCloud アカウントにログインした後、サーバー → サーバーのデプロイに移動して、新しい VPS インスタンスを作成するプロセスを開始できます。 .
UpCloud は世界中に多くのデータセンターを持っています。新しいサーバーをホストするために最も近い場所を選択してください。次に、仮想マシンにどれだけのリソースを割り当てるかについてのプランを選択する必要があります。 Jenkins は多くのリソースを使用しませんが、Xilinx Vivado は実際に RAM を大量に消費します。したがって、下の図に示すように、少なくとも 4 GB の RAM を備えたプランを選択する必要があります。
メモリ使用量はターゲット FPGA の複雑さに密接に関係しているため、ザイリンクスのメモリに関する推奨事項のページを参照することをお勧めします。このページには、私が使用している Zynq-7000 XC7Z045 FPGA のピーク メモリ使用量が 1.9 GB とリストされています。 2 GB プランではデザインを配線するには少なすぎることがわかりました。 Vivado がクラッシュし、dmesg に次のメッセージが表示されました。 ログ:
[807816.678940] メモリ不足:強制終了されたプロセス 22605 (vivado) total-vm:2046684kB、anon-rss:782916kB、file-rss:308kB、shmem-rss:0kB
サーバーの RAM と CPU リソースは、UpCloud アカウント内からいつでも簡単にアップグレードできることに注意してください。 VPS のファイルシステムのパーティションを再分割しない限り、より高価なパッケージに付属する追加のハードドライブ容量を自動的に取得することはできませんが、実行は可能です。参考までに、私は 50 GB のストレージのプランで開始し、オートメーション サーバー全体を完成させた後、その 61% を使用しました。 Vivado だけで 24 GB のスペースが必要です。
以下の図に示すように、オペレーティング システムとして最新の CentOS Linux ディストリビューションを選択することをお勧めします。 Xilinx Vivado は、無料ではない Red Hat Linux のみを正式にサポートしています。ただし、CentOS はコミュニティによってサポートされている無料の Linux ディストリビューションであり、Red Hat に厳密に準拠しています。
次に、デフォルトのままにできるネットワークに関するオプションがいくつかあります。 Web ページには、パスワードなしでログインするために SSH キーをアップロードできるセクションもあります。これらの設定は、SSH キーをアップロードするための従来の Linux 方法を使用して、後からいつでも行うことができます。
最後に、以下の図に示すように、サーバーのホスト名と名前を指定する必要があります。ホスト名は、ユーザーが Jenkins サーバーにアクセスするためにブラウザーに入力するパブリック ドメインです。ドメインまたはサブドメインを用意していない場合でも、IP アドレスを使用していつでもサーバーにアクセスできます。設定に問題がなければ、デプロイボタンを押します。 ボタンをクリックしてサーバーを作成します。
サーバーを作成すると、自動生成されたパスワードが通知として表示されます。これは、Linux の passwd を使用して後で変更できます。 コマンド。サーバーを展開する前に SSH キーを指定した場合は、パスワードはまったく必要ありません。サーバーにアクセスできなくなった場合でも、コンソール接続を開くをクリックすることで、UpCloud アカウント内からいつでもログインできます。 、下の画像に示すように。
DNS ゾーンの設定
新しいサーバーには、UpCloud アカウントの サーバー -> ネットワーク にある永続的な IPv4 および IPv6 アドレスが割り当てられます。 。パブリック IPv4 アドレスの root アカウントに SSH 接続することで、サーバーにアクセスできます。
以下の画像の IP アドレスの例を使用すると、Linux ホーム コンピュータに入力する適切なコマンドは次のようになります。
実験として行う場合は、IP アドレスのみを使用しても問題ありません。しかし、より現実的な解決策は、サーバーに永続的なドメイン名を割り当てることです。そのためには、オンラインで利用できる多数のレジストラの 1 つからドメインを購入する必要があります。
私はすでに vhdlwhiz.com ドメインを所有しているため、jenkins.vhdlwhiz.com という名前の Jenkins サーバーのサブドメインを作成することにしました。 。 UpCloud サーバーを展開したときに、ドメイン名を UpCloud サーバー上に正しく設定しました。次に行う必要があるのは、サブドメインがパブリック IPv4 アドレスを指すようにすることです。
下の画像は、ドメイン名レジストラーの DNS ゾーン ファイルに入力している設定を示しています。サーバーをトップ ドメイン (vhdlwhiz.com) に置く場合は、ホスト名フィールドを空白のままにしておくでしょう。ただし、これを vhdlwhiz.com の「jenkins」サブドメインに置きたいと考えています。したがって、サブドメインの名前を入力します。
DNS 設定を変更した後、ドメイン名を使用して Web サイトにアクセスできるようになるまで、しばらく時間がかかります。通常は 20 分もかかりませんが、極端な場合には、変更がインターネットの隅々まで伝わるまでに最大 48 時間かかることがあります。
変更が有効になると、SSH 経由でサーバーにログインするときに IP アドレスの代わりにドメイン名を使用できるようになります。
ssh root@yoursub.yourdomain.com
Jenkins のインストール
新しい Linux サーバーの root アカウントにログインした後に最初に行うべきことは、インストールされているすべてのパッケージを更新することです。 CentOS Linux では、yum はデフォルトのパッケージマネージャーです。 yum を使用します。 ほとんどのソフトウェアをインストールするためのコマンド。
次のコマンドを発行して、インストールされているすべてのパッケージを最新バージョンに更新します。
システムが最新であることがわかったので、インストールを続行できます。ただし、yum を発行する前に Jenkins をインストールするコマンドを使用して、Java バージョン 11 を明示的にインストールします。これにより、後で Xilinx Vivado をインストールするときに問題が発生しなくなります。
現在、サーバーには Java インタプリタが存在しないため、yum と指示すると Jenkins をインストールするには、Java バージョン 8 がインストールされます。これは Jenkins ではうまく機能しますが、Vivado は Java バージョン 11 に依存しているため、後で問題が発生します。
Jenkins をインストールする前に、次のコマンドを使用して Java 11 をインストールします。
yum -y install java-11-openjdk-devel
Jenkins は、CentOS に付属するデフォルトのソフトウェア リポジトリでは利用できません。幸いなことに、次のコマンドを使用して、Red Hat から Jenkins リポジトリをインポートできます。
wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat/jenkins.repo rpm --import https://pkg.jenkins.io/redhat/jenkins.io.key
最後に、Jenkins のインストールに進みます。
Jenkins サーバーは次回の起動後に自動的に起動しますが、次のように再起動せずにサーバーを起動することもできます。
systemctl を使用すると、いつでも Jenkins サーバーのステータスを確認できます。 コマンド:
サーバーのステータスとエラー メッセージが出力されます。
安全でない HTTP を介した Jenkins
この時点で、Jenkins は VPS のポート 8080 で実行されていますが、Web ブラウザーで Jenkins に接続する方法はありません。これは、CentOS ファイアウォールがデフォルトでポート 8080 とポート 80 (HTTP) をブロックするためです。これを修正するためにできることは、ファイアウォールでポート 80 を開き、iptables を使用してポート 8080 に再ルーティングすることです。 .
ただし、その前に、サイトを HTTPS で保護するかどうかを決定する必要があります。 HTTP とポート 80 のみを使用する場合の問題は、Web サイトが安全でなくなることです。公衆 Wi-Fi を使用してアクセスしている場合、同じ Wi-Fi 上で悪意のある人物がラップトップとすぐに入手できるハッキング ソフトウェアを使用して接続を盗聴し、Jenkins へのログイン認証情報を盗む可能性があります。
暗号化されていない HTTP によるセキュリティ リスクを回避したい場合は、Jenkins の HTTPS の設定に関する次のセクションに進んでください。それ以外の場合は、 読み続けてください。
Jenkins への安全でない HTTP アクセスを有効にするのは、次のコマンドを発行するのと同じくらい簡単です。
firewall-cmd --permanent --zone=public --add-port=80/tcp firewall-cmd --reload iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
次に、お気に入りのブラウザにドメイン名を入力すると、Jenkins のスタートガイドが表示されます。 ページが表示されるはずです。少なくとも Google Chrome では、以下の画像に示すように、アドレス バーに「安全ではありません」という警告が表示されます。
Jenkins のセットアップに進んでください。 よろしければセクションをご覧ください。
安全な HTTPS 経由の Jenkins
安全でない Web サイトを一般公開することは、セキュリティ上の大きなリスクとなります。 Jenkins はソース コードにアクセスでき、サーバーへの侵入に成功したハッカーも同様にアクセスできます。幸いなことに、Web サイトの保護は、コマンドをいくつかコピーして貼り付けるだけで完了します。
Jenkins だけでは HTTPS を処理できません。したがって、安全なチャネルを介して到着したリクエストを安全でない Jenkins サーバーに再ルーティングするために、汎用 Web サーバーをインストールする必要があります。 Nginx を使用します。これは、現在最も人気のある無料のオープンソース Web サーバーの 1 つです。
次のコマンドを発行して、Nginx をインストールして起動します。
yum -y install nginx systemctl start nginx
次に、ファイアウォールで HTTP ポートと HTTPS ポートの両方を開く必要があります。 HTTPS リクエストのみを処理しますが、すべての安全でないリクエストを安全なポートにリダイレクトするように Nginx を設定するため、HTTP ポートも開いたままにしておく必要があります。
これらのコマンドは、Web トラフィック用のファイアウォールを開きます。
firewall-cmd --permanent --zone=public --add-port=80/tcp firewall-cmd --permanent --zone=public --add-port=443/tcp firewall-cmd --reload
次のステップは、Web ブラウザーが対話しているのがあなたの Web サイトであり、偽者ではないことを証明するために使用できる証明書をインストールすることです。無料の Let’s Encrypt 認証局を使用してサイトを保護します。個々の手順は複雑ですが、幸いなことに、certbot はそれを自動的に実行できるスクリプトを提供します。
次のコマンドを使用してスクリプトをダウンロードして準備します。
apt update apt install snapd snap install core; snap refresh core snap install --classic certbot
次に、スクリプトを実行します。これにより、証明書がインストールされ、Nginx 構成ファイルに必要な変更が加えられます。
スクリプトを実行すると、情報の入力を求めるプロンプトが表示されます。 HTTP トラフィックを HTTPS にリダイレクトするかどうかを選択するまで、すべての質問に肯定 (はい、受け入れる) で答えてください。以下のリストは、質問と私が提案する回答 (2) を示しています。 Nginx が安全でないリクエストをリダイレクトできるようにすると、誰も http:// を明示的に入力できなくなります。 yoursite.com そして、Jenkins の安全でないバージョンにアクセスします。 Nginx はそれらを安全なバージョンにリダイレクトします。
... Deploying Certificate to VirtualHost /etc/nginx/nginx.conf Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1: No redirect - Make no further changes to the webserver configuration. 2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for new sites, or if you're confident your site works on HTTPS. You can undo this change by editing your web server's configuration. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
最後に、cron ジョブを有効にして証明書を定期的に更新する必要があります。そうしないと有効期限が切れて、ブラウザはサイトを開くことをまったく拒否します。
次のワンライナー コマンドを発行して、毎日の cron ジョブを追加します。
echo "0 0 * * * /snap/bin/certbot renew --quiet" | crontab -
cron デーモンは毎日深夜に更新スクリプトを実行します。 crontab -l を使用して cron ジョブを一覧表示できます。 コマンドを実行し、crontab -e で編集します。 コマンド。ここで Web サイトにアクセスすると、Jenkins ではなく、Nginx テスト ページが表示されます。この問題はすぐに修正しますが、下の画像に示すように、Chrome アドレス バーから「安全ではありません」という警告が消えていることを確認してください。
Nginx が Jenkins に対応できるようにするには、/etc/nginx/nginx.conf にいくつかの変更を加える必要があります。 ファイル。このコード スニペットのクレジットは、Medium 上の Kerren のブログに与えられます。 nano エディタを使用するのが、おそらく設定ファイルを編集する最も簡単な方法です。
nano /etc/nginx/nginx.conf
ドメイン名がリストされているサーバー ブロックを見つけて、以下のリストで強調表示されている行を nginx.conf ファイルに追加します。 3 つの新しい行のうち最初の行はサーバー ブロックの上にあり、残りはルート ロケーション ブロックにあることに注意してください。
構成ファイルを更新した後、変更を有効にするために Nginx をリロードする必要があります。オプションで、次のコマンドを使用して、リロードする前に設定ファイルをテストできます。
Nginx は OK を出力するか、nginx.conf のどの行にあるかを通知します。 ファイルのエラーは次のとおりです。変更に問題がなければ、次のコマンドを実行して Web サーバーをリロードできます。
ブラウザで Jenkins サイトにアクセスすると、以下の画像に示すように、Jenkins の [はじめに] ページが表示されるはずです。今回は安全な接続を介して提供されるため、Web GUI インターフェイス内から安全に Jenkins の設定を続行できます。
Jenkins のセットアップ
初めて Jenkins Web サイトにアクセスすると、Linux ファイル システム上のファイルで見つかったパスワードの入力を求められます。 SSH 経由でログインしているときに、次のコマンドを使用してパスワードを表示します。これをコピーしてブラウザに貼り付けて、Web GUI にアクセスします。
cat /var/lib/jenkins/secrets/initialAdminPassword
次の画面で、Jenkins は、提案されたプラグインをインストールするかどうか、またはインストールするプラグインを指定するかどうかを尋ねます。 推奨プラグインをインストールしてください。 今のところオプション。プラグインは後でいつでも追加または削除できます。
次のページでは、管理者ユーザーを作成する必要があります。詳細を入力し、新しいアカウントで使用する強力なパスワードを作成します。デフォルトでは、ログインしたユーザーのみが Jenkins サーバーにアクセスできます。匿名ユーザーが Web サイトにアクセスした場合にのみ、ログイン ダイアログが表示されます。あなたが私の * デモ サイト jenkins.vhdlwhiz.com にアクセスできた唯一の理由 サーバーに変更を加えたということです。 Matrix Authorization Strategy プラグインを使用して、一部のビューへの匿名アクセスを許可しました。
* 更新:2020 年 5 月 13 日にデモ サイトを削除しました
Jenkins のプラグインのインストールが完了すると、「Jenkins の準備ができました!」というメッセージが表示されます。上の画像に示すように、メッセージが表示されます。ボタンをクリックすると、新しい Jenkins インストールの空の概要ページが表示されます。
Jenkins プラグインのインストール
最初に行う必要があるのは、多数のプラグインをインストールすることです。 Jenkins には、拡張機能のインストール、更新、削除に使用できるプラグイン マネージャーが組み込まれています。ほとんどのニーズに対応できるプラグインが見つかります。 Jenkins に機能を追加する必要がある場合は、プラグイン マネージャーの検索機能を使用してください。
サンプルの Jenkins サーバーをセットアップするときに使用したプラグインのインストールに進みましょう。サイドバーから、Jenkins の管理 -> プラグインの管理 -> 利用可能を選択します。 。検索フィールドに何かを入力しない限り、プラグインはリストされないことに注意してください。入力すると、それらが表示されます。
ブルーオーシャン
インストールすることをお勧めする最初のプラグインは、Blue Ocean という名前です。このプラグインは、Jenkins ワークフローとユーザー インターフェイスを最新化したものです。また、他の便利なプラグインも多数取り込まれているため、個別にインストールする必要はありません。以下の画像に示すように、プラグイン マネージャーで「blue Ocean」を検索し、インストール用に選択します。
[インストール] をクリックした後に表示されるインストール進行状況ページには、インストールが完了しジョブが実行されていないときに Jenkins を再起動する を選択するオプションがあります。 。その横のボックスにチェックを入れると、プラグインのインストールが完了した後に Jenkins が再起動します。 Jenkins を再起動するもう 1 つの方法は、SSH 経由でサーバーにログインし、次のコマンドを実行することです。
systemctl restart jenkins
Blue Ocean によってインストールされた他のプラグインの長いリストを除けば、一見しただけでは目立った変化はありません。ただし、以下の画像に示すように、サイドバーに新しいメニュー項目が表示されます。クリックすると、Blue Ocean GUI が表示されます。この GUI は、通常の Jenkins インターフェイスとはまったく異なります。試してみてください!
緑色のボール
私がいつもインストールする次のプラグインは、純粋に美しさのためのものです。 Green Balls プラグインには設定は必要ありません。プラグイン マネージャーで「緑色のボール」を検索し、下の画像に示すようにインストールするだけです。
デフォルトでは、Jenkins は概要ページで青色のボールを使用して、ジョブのステータスが成功であることを示します。その理由は、Jenkinsの発明者が日本人であることが関係しています。興味深いことに、日本では、OK ステータスを示す色として青が緑と交換可能です。詳細については、この記事で著者がその理由を直接説明するのを聞くことができます。
世界の他のほとんどの地域のユーザーは、おそらく緑色のステータス ボールを好むでしょう。これは、下の画像に示すように、Green Balls プラグインで簡単に修正できます。
ロケールプラグイン
次にインストールしたプラグインは Locale という名前です。 利用可能で「locale」を検索します。 プラグインマネージャーのタブ。下の図に示すように、プラグインをインストールします。
このプラグインを使用すると、Jenkins ですべてのユーザーの GUI で同じ言語を使用するように強制できます。デフォルトでは、Jenkins はユーザー インターフェイスを Web ブラウザーが使用している言語に翻訳します。私はノルウェー人ですが、Jenkins は英語で使いたいと思っています。翻訳が少し不十分でした。また、Jenkins で何かを行う方法を調べる必要がある場合は、英語で Google で答えを検索する方がはるかに簡単です。
もちろん、このプラグインが必要かどうかは完全にあなた次第です。インストールする場合は、Jenkins の管理 -> システムの構成に移動する必要があります。 Locale というセクションを見つけます。 。次に、下の画像に示すように、「en_US」(または任意の言語) を入力し、下のボックスにチェックを入れて、この言語をすべてのユーザーに強制する必要があります。ページの一番下までスクロールして [保存] をクリックすることを忘れないでください。 .
私のセットアップのクローンを作成するために必要な最後のプラグインは、Sidebar Link プラグインです。 Jenkins サイドバーにカスタム リンクを追加できます。後でこれを使用して、FPGA リリース (ビットファイル) へのリンクを追加します。以下の画像に示すように、プラグイン マネージャーで「サイドバー」を検索し、プラグインをインストールします。
Jenkins を GitHub に接続する
リポジトリがパブリックかプライベートかに関係なく、GitHub アカウントに対して Jenkins にいくつかの権限を与える必要があります。少なくとも、最も簡単な方法でそれを実行したい場合は、Jenkins GitHub プラグインに GitHub とのインターフェイスを管理させる必要があります。 Blue Ocean はすでに GitHub プラグインをインストールしています。これを構成する手順は次のとおりです。
まず、システムに Git をインストールする必要があります。 GitHub プラグインは厳密には必要ありませんが、Jenkins ジョブの操作を開始する場合は、これが必要です。次のコマンドを発行して、CentOS Linux に Git をインストールします。
GitHub の個人アクセス トークン
GitHub にサインインし、右上隅にあるプロフィール写真をクリックして設定を選択し、開発者設定に移動します。 。次に、個人アクセス トークンを選択します。 左側のサイドバー メニューからアクセスするか、このリンクをクリックすると直接そこに移動します。
ここで、[新しいトークンの生成] をクリックする必要があります。 、下の画像に示すように。 GitHub ではもう一度パスワードの入力を求められます。ここで行っていることは、基本的に、アプリケーション固有の新しいパスワードを作成することです。これは、パスワードを取り消すことができ、トークンに付与されるアクセス許可を制限できるため、実際のパスワードを共有するよりも優れています。それが、開いたページで行うことです。
パスワードを入力したら、トークンに名前を付ける必要があります。その名前はあなただけのものです。たとえば「Jenkins」など何でも構いません。次に、少なくとも admin:org_hook を有効にする必要があります。 、管理者:repo_hook 、およびリポジトリ 以下の図に示すように、アクセス許可。他のすべてのボックスはチェックを外したままにしておいても問題ありません。
最後に、[トークンの生成] をクリックすると、 , アクセスコードが表示されます。再度見ることはできないため、そのページを離れる前にコピーする必要があります。忘れた場合は、トークンを削除して再作成してください。
Jenkins での GitHub 認証情報の入力
トークンをコピーしたら、Jenkins に移動し、Manage Jenkins -> Configure System を選択します。 をクリックし、GitHub というセクションを見つけます。 、下の画像に示すように。ドロップダウン メニューから、[GitHub サーバー -> GitHub サーバーの追加] を選択します。 .
表示される新しい GitHub サーバー セクションで、フックの管理というラベルの付いたボックスをオンにします。 。これを行うと、Jenkins は監視しているリポジトリの GitHub に Webhook をインストールします。ユーザーが関連する GitHub リポジトリにコードをプッシュするときに、これらを使用してシミュレーションをトリガーしたり、Jenkins でビルドしたりするため、これが特に便利であることが後でわかります。
資格情報 (追加) -> Jenkins を選択します。 下の画像に示すように、ボックスをチェックした後。
開いたウィンドウで種類を変更します。 秘密のテキストへのドロップダウン 。次に、以前に GitHub で生成した個人用アクセス トークンをシークレットに貼り付けます。 フィールド。 ID フィールドに「GitHub」と入力し、追加を押します。 .
最後に、メインの設定メニューに戻ったら、秘密のテキストを追加した後、新しい GitHub を選択します。 認証情報のキー メニュー。次に、接続のテストを押します。 Jenkins がアクセス トークンを使用して GitHub と通信できることを確認します。すべてがうまくいけば、下の画像に示すようなメッセージが表示されるはずです。
必ずページの一番下までスクロールし、[保存] をクリックしてください。 設定ページを離れる前に。
問題が発生し、複数の認証情報を追加することになった場合は、「Jenkins の管理」->「ユーザーの管理」に移動して認証情報を削除できます。 をクリックし、ユーザー名をクリックします。左側のサイドバーに、認証情報という名前のメニュー項目が表示されます。 。そこから、Jenkins が保存したすべてのキーを表示および編集できます。
Jenkins からメールを送信する
コードに何か問題があった場合に自動メールを送信するように Jenkins を構成します。これを実現するには、Manage Jenkins -> Configure System でいくつかの変更を加える必要があります。 メニュー。
最初に行う必要があるのは、Jenkins が自動メールを送信するときに使用する差出人アドレスを入力することです。 システム管理者の電子メール アドレスを見つけます。 設定ページのフィールドに、Jenkins の送信元となるアドレスを入力します。
ちょっとした注意事項:Jenkins ドメイン名で終わるアドレスを入力することをお勧めします。これにより、電子メールがスパム フォルダーに入る可能性が最小限に抑えられます。 Jenkins サーバーには、他のドメインに代わって電子メールを送信する権限がありませんが、ほとんどの電子メール サービスは、送信サーバーと同じドメインの差出人アドレスを受け入れます。詳細については、このウィキペディアの記事をご覧ください。下の画像では、Jenkins サーバーと同じドメインで終わる差出人アドレスを入力しました。
次に、Jenkins に電子メールを送信する方法を提供する必要があります。これを行う最も簡単な方法は、VPS に SMTP (メール) サーバーをインストールすることです。これを行うには、ログインして次のコマンドを発行します。
yum -y install sendmail systemctl enable sendmail systemctl restart sendmail
sendmail をインストールした後 、Jenkins システム構成に戻り、SMTP サーバーに「localhost」と入力します。 以下の画像に示すように、フィールドに入力します。
この時点で、チェックボックスをオンにして、未登録ユーザーへの送信を許可することもできます。これは、Jenkins ユーザー アカウントを持たないユーザーを意味します。後で、欠陥のあるコードを GitHub にプッシュした人に電子メールを送信するように Jenkins を構成します。 Jenkins は GitHub から犯人の電子メール アドレスを取得しますが、それが機能するのは、その人物が一致する Jenkins アカウントを持っている場合、またはこのボックスをオンにした場合に限られます。
最後に、上の画像に示すように、構成をテストできます。 設定のテストを押した後 をクリックすると、「メールが正常に送信されました」というメッセージが表示され、メールが受信箱に届くはずです。 5 分以内にメールが届かない場合は、スパム フォルダを確認してください。
バッチ モードでの Xilinx Vivado のインストール
このサンプル プロジェクトでは、Xilinx Vivado を使用してコードをシミュレート、コンパイル、実装しています。ターゲット デバイスは、ZebBoard 開発ボード上の Xilinx Zynq-7000 FPGA です。このセクションでは、無料の WebPACK ライセンスを使用して Vivado を VPS にインストールする方法を説明します。
最初のステップは、次の図に示すザイリンクス統合インストーラー:Linux 自己解凍 Web インストーラーをダウンロードすることです。インストーラーをダウンロードするには、ログインするか、新しいザイリンクス アカウントを作成する必要があります。
ダウンロードが完了したら、デスクトップ コンピューターから Jenkins サーバーにコピーする必要があります。デスクトップ上の Linux シェルにアクセスできる場合は、次のコマンドのように安全なファイル コピーを使用することをお勧めします。
インストーラーを実行する前に、Vivado の依存関係を満たすためにいくつかのパッケージをインストールする必要があります。これを行うには、次のコマンドを実行します。
yum -y install tar yum -y install java-11-openjdk-devel yum -y install ncurses-compat-libs yum -y install gcc
次に、次のようにザイリンクス統合インストーラーを実行します。
./Xilinx_Unified_2019.2_1106_2127_Lin64.bin --keep --noexec --target Xil_installer
.bin ファイルは、Xil_installer という名前の新しいディレクトリにインストール ファイルを解凍します。 。代わりに以下のエラーが表示される場合は、tar がインストールされていないことが原因です。 .
Verifying archive integrity... All good. Uncompressing Xilinx InstallerExtraction failed. Terminated
ザイリンクス統合インストーラーを使用すると、さまざまなザイリンクス ツールをシステムにインストールできます。したがって、xsetup を実行する必要があります。 Xil_installer 内のファイル ディレクトリを使用して、関心のあるソフトウェアを指定します。
cd Xil_installer/ ./xsetup -b ConfigGen
xsetup スクリプトは、どのツールを使用するかを尋ねます。 Vivado の場合は「2」を入力します。 、Vivado HL WebPACK の場合は「1」 、以下のリストに示すように。
Select a Product from the list: 1. Vitis 2. Vivado 3. On-Premises Install for Cloud Deployments 4. BootGen 5. Lab Edition 6. Hardware Server 7. Documentation Navigator (Standalone) Please choose: 2 Select an Edition from the list: 1. Vivado HL WebPACK 2. Vivado HL Design Edition 3. Vivado HL System Edition Please choose: 1
ザイリンクス WebPACK エディションをインストールするには、インストール中にザイリンクス アカウントにログインする必要があります。デスクトップ コンピューターでは、インストーラー GUI によってこのプロセスがガイドされますが、サーバーでは GUI がないため、xsetup を使用して認証する必要があります。 スクリプト。次のコマンドを実行して認証トークンを生成します。
機能するまでにコマンドを数回実行する必要がありました。最初、スクリプトは「インターネット接続が検証されました。インターネットに接続できます。」というエラーで停止しました。しかし、数回試した後、成功し、サインインすることができました。スクリプトはユーザー ID とパスワードを要求します。これは、xilinx.com からインストーラーをダウンロードするときに使用した電子メールとパスワードです。
最後に、Vivado をバッチ モードでインストールする準備が整いました。セットアップ スクリプトを呼び出すときは、xsetup が実行されるようにインストール構成ファイルを指定する必要があります。 どのツールをダウンロードすればよいか知っています。コンフィギュレーション ファイルは .Xilinx にあります。 root ユーザーのホームディレクトリ内のフォルダー。次のコマンドを実行して、構成ファイルを使用してインストールを開始します。
./xsetup -a XilinxEULA,3rdPartyEULA,WebTalkTerms \ -b Install -c ~/.Xilinx/install_config.txt
インストールプロセスが完了するまでに長い時間がかかります。 Vivado のインストールでは 24 GB のスペースが使用されます。これらはすべて、比較的遅いザイリンクス サーバーからダウンロードされています。私の場合、ダウンロードには 2 時間強かかりました。
インストールが完了したら、Vivado がバッチ モードで正常に起動するかどうかをテストする必要があります。ザイリンクスでは、環境をセットアップするシェル スクリプトを提供しています。 Vivado を実行する前に、ソースを使用する必要があります。 command to load the content of the script into your active shell:
source /tools/Xilinx/Vivado/2019.2/settings64.sh
Then, you are ready to run Vivado. But there’s no GUI environment installed on your server, so we have to start it in batch mode by using this command:
If Vivado starts and exists immediately without printing any errors, it’s an indication that Vivado has everything it needs, and you are ready to go. Note that if you are getting the error listed below, it’s because you haven’t installed the ncurses-compat-libs package, as we talked about at the start of this section.
application-specific initialization failed: couldn't load file "librdi_commontasks.so": libtinfo.so.5: cannot open shared object file: No such file or directory
Integrating Vivado in Jenkins
To prepare Jenkins for Vivado, we need to make some changes to the general settings. Head to Manage Jenkins->Configure System and check that all the default settings make sense for you.
As I mentioned earlier, Vivado uses a lot of RAM. The resource usage depends on your target FPGA, and you can get an indication of how much you need from the Xilinx Memory Recommendations page. Therefore, I recommend that you change the default number of parallel jobs that can run from 2 to 1. Unless you allocated vast RAM resources on your VPS, you probably want to set # of executors to 1, as shown in the image below.
Instead of defining the environment variables in every Jenkins job, we will specify the PATH globally for all jobs. That makes it easier for you to swap to a newer version of Vivado in the future. Then you can refer to the ‘vivado’ executable in your scripts, and it will always point to the latest version, or whichever you decide.
Scroll to the Global properties section and check Environment variables 。 Click Add to get a new entry. Make sure to include the standard Linux PATH 同様に。 I used “PATH=/tools/Xilinx/Vivado/2019.2/bin:/sbin:/usr/sbin:/bin:/usr/bin”, as shown in the image below.
Don’t forget to scroll to the bottom of the page and click Save .
Vivado GUI projects in batch mode
I chose to manage the Vivado projects in GUI mode. For each repository, I created a new project from within the regular Vivado GUI, adding source files, setting libraries, and all of that. However, the .xpr project files are binary and depend on a lot of other temporary files in the project directory.
Binary files are not suitable for SCMs like Git. Fortunately, Xilinx has thought of this and written a guideline (XAPP1165) for how to use Vivado with version control systems. What we do is to use the write_project_tcl command in Vivado to export the entire project into a Tcl script. The script contains human-readable Tcl code suitable for Git.
I’ve organized all of the Git repos so that all files that belong to the Vivado projects are in a subfolder named “vivado”, while the VHDL source files are in the parent directory. Check out the demo packages project on my GitHub to see what I mean. For each repo, we will put the Vivado Tcl scripts in the vivado folder. You will also find the create_vivado_proj.tcl file, which is the human-readable version of the Vivado project.
To create the create_vivado_proj.tcl file, start by setting up the Vivado project as you wish in the Vivado GUI. Make sure that the Vivado project resides within a vivado subfolder. When you’re happy with the project, export it by entering the following commands in the Vivado Tcl console:
cd [get_property DIRECTORY [current_project]] write_project_tcl -force -target_proj_dir . create_vivado_proj
Add the create_vivado_proj.tcl file to Git, and set up the gitignore to ignore the rest of the Vivado project. Here’s the content of my .gitignore file which ignores everything but Tcl scripts in the vivado folder:
Opening the Vivado project in batch mode
It’s a good idea to test the Vivado project manually on the VPS before you start creating Jenkins jobs. By default, the daemon runs from a user account named jenkins on the Linux server. Therefore, you should test the Vivado project using the jenkins user.
Make sure that you have Git installed on the Linux server before you start this experiment. Run this command to install Git after logging in as root:
You can’t log in to the jenkins user directly, but you can change to it from the root user like this:
If you now run a pwd command, you will see that you are at /var/lib/jenkins :
[jenkins@jenkins ~]$ pwd /var/lib/jenkins
That’s because this isn’t a regular user account that has the home directory under /home , as is the norm on Linux systems. It’s only for running the Jenkins daemon, but we can log in to perform a manual walkthrough of the build process in the Jenkins environment.
The home folder is full of all the dynamic data like logs, user settings, and plugins that you have downloaded. When we later start running jobs in the Jenkins GUI, they will appear in the jobs folder.
Let’s go to the jobs folder to perform our experiment:
cd /var/lib/jenkins/jobs/
You can clone your Git repository directly into the jobs folder. Your Git repo has to be accessible without using a password. Either because it’s public, or because you have set up passwordless login as described on the GitHub help pages.
If you don’t have a Git repository with the Vivado project ready, feel free to clone one of my repos like this:
git clone https://github.com/jonasjj/Jenkins-demo-packages
Then, cd into the new directory of the Git repository, and further into the vivado folder:
cd Jenkins-demo-packages/vivado/
If you downloaded my example, you would find two Tcl files:create_vivado_proj.tcl and check_syntax.tcl 。 The first one is the Vivado project converted to a Tcl file, and the second one is a script that we haven’t talked about yet. It’s for checking the syntax of VHDL files in the Vivado project.
Before we can run any Vivado command, we need to set the PATH environment variable in the current shell. In Jenkins, we solved this by using Global properties , but now we are not coming through Jenkins, so we have to source the setup script from Xilinx like this:
source /tools/Xilinx/Vivado/2019.2/settings64.sh
Now that the vivado executable is in our path, let’s start by recreating the project. This is the command for doing that when running Vivado in batch mode:
vivado -mode batch -source create_vivado_proj.tcl
After you hit Enter, you should see a whole lot of Tcl code echoed to the console. It’s the code for recreating the Vivado project that’s executing. If you didn’t see any obvious errors, type the command “echo $?” in the terminal before you do anything else. The output should be 0 if everything went well, as we can see from the listing below.
INFO: [Common 17-206] Exiting Vivado at Sun Apr 19 18:32:48 2020... [jenkins@jenkins vivado]$ echo $? 0
The “echo $?” command shows you the exit status from the previous command that you executed in Linux. An exit status of 0 means that everything is OK, no error. Any other exit status than 0 is an indication of error. Those are old Unix conventions that you can read more about here. Anyway, the exit status is important for Jenkins because that’s how it decides if a job stage is a success or a failure.
If you now do a directory listing, you will see that Vivado has recreated the project’s binary files:
[jenkins@jenkins vivado]# ls -la total 72 drwxrwxr-x. 6 jenkins jenkins 4096 Apr 19 18:32 . drwxrwxr-x. 4 jenkins jenkins 4096 Apr 19 18:18 .. -rw-rw-r--. 1 jenkins jenkins 217 Apr 19 18:18 check_syntax.tcl -rw-rw-r--. 1 jenkins jenkins 23375 Apr 19 18:18 create_vivado_proj.tcl drwxrwxr-x. 3 jenkins jenkins 16 Apr 19 18:32 packages.cache drwxrwxr-x. 2 jenkins jenkins 26 Apr 19 18:32 packages.hw drwxrwxr-x. 2 jenkins jenkins 6 Apr 19 18:32 packages.ip_user_files -rw-rw-r--. 1 jenkins jenkins 9314 Apr 19 18:32 packages.xpr -rw-rw-r--. 1 jenkins jenkins 638 Apr 19 18:32 vivado.jou -rw-rw-r--. 1 jenkins jenkins 20153 Apr 19 18:32 vivado.log drwxrwxr-x. 2 jenkins jenkins 6 Apr 19 18:32 .Xil
Let’s try another experiment with running Tcl scripts in Vivado batch mode. Create a one-liner Tcl script by using the following command:
Now, run the script in Vivado batch mode:
vivado -mode batch -source test.tcl
After Vivado closes, check the exit code once more using the “echo $?” command:
[jenkins@jenkins vivado]# echo $? 1
It’s 1, which means exit failure in Unix. If you change the content of the test.tcl script to “exit 0”, and run Vivado once again, you will see that the exit status is now 0, indicating success. Try it!
The exit keyword is standard Tcl. We are going to use it as the interface between Vivado and Jenkins. Jenkins runs whatever Tcl script we create in Vivado, and looks at the exit status to determine if it shall mark the job stage as success or failure.
Remember to delete our little test project from the jobs folder when you are happy with the experiment:
cd /var/lib/jenkins/jobs/ [jenkins@jenkins jobs]# rm -rf Jenkins-demo-packages
Tcl script for checking code syntax in Vivado
This Tcl script runs a syntax check of the VHDL files in the project. If you are going to simulate or implement the code, you won’t need this script because any syntax errors will break the compilation. But for my packages project, it doesn’t make any sense to create a testbench for it. The files just contain constant and types declarations. I still want to catch any coding errors pushed to this repo, and that’s where the syntax check comes in handy.
In the script that is listed below, we start by opening the project file. Then, we call the Vivado check_syntax command while telling it to save the output to a variable called msg 。 After the check has completed, we look at the output message to see if there were any errors reported. If check_syntax reported anything at all, we set the exit status to 1 (failure). If there were no errors, we exit 0 (success).
check_syntax.tcl:
# Check for syntax errors
# Return exit code 1 on error, else 0
open_proj packages.xpr
set msg [check_syntax -fileset sim_1 -return_string]
set ret_val 0
if {$msg != ""} {
set ret_val 1
}
puts $msg
exit $ret_val
Vivado supports all of the standard Tcl keywords, and there are also a lot of built-in commands like check_syntax. I recommend taking a look at these two Xilinx documents that cover the Tcl scripting capabilities in great detail:
Vivado Design Suite Tcl Command Reference Guide (UG835)
Vivado Design Suite User Guide Using Tcl Scripting (UG894)
Tcl script for simulating in Vivado
The next script that I created is for running the testbench in batch mode. For this to work, you have to configure the simulation sets in the Vivado GUI before you export the project to Tcl. Go ahead and recreate one of the simulation projects on your desktop computer using the create_vivado_proj.tcl script to see how I set it up beforehand. You can open the reconstructed projects in the Vivado GUI.
As you can see from the listing below, I start by opening the project. Then, I set the name of the simulation fileset to a variable (usually sim_1 ). After we launch the simulation, we also have to close it. Otherwise, the status of the simulation won’t get written to the log files.
run_simulation.tcl:
open_proj seg7.xpr set sim_fileset sim_1 launch_simulation -simset [get_filesets $sim_fileset] close_sim # Look for assertion failures in the simulation log set log_file [glob *sim/$sim_fileset/behav/xsim/simulate.log] set fp [open $log_file] set file_data [read $fp] exit [regex "Failure:" $file_data]
Now, I struggled to find a good way of getting the simulation status. My VHDL testbenches terminate on a VHDL finish keyword on success. Errors will result in a VHDL assertion failure. There’s no obvious way to find out why the simulator stopped by using Tcl commands in Vivado.
Fortunately, Tcl is a powerful scripting language. My workaround is to open the simulation log and look for the string “Failure:”, which indicates a VHDL assertion failure. Finally, we exit 1 if the word is in the log, or 0 if it isn’t.
Tcl script for synthesizing in Vivado
In the Tcl script for synthesizing in Vivado batch mode, we start by opening the project file. Then, We assign the run name to a variable. You must have added the design files to the Vivado project before you exported it to Tcl. If you didn’t change the name of the synthesis run in the GUI, it’s will probably be “synth_1”.
You should set the CPU count variable to the number of logical processors that your server has. This number controls the degree of multithreading that Vivado uses. I opted for the VPS with 4 CPUs on UpCloud, and therefore set the CPU count to 4.
run_synthesis.tcl :
open_proj seg7.xpr
set run_name synth_1
set cpu_count 4
reset_runs $run_name
launch_runs $run_name -jobs $cpu_count
wait_on_run $run_name
set status [get_property STATUS [get_runs $run_name]]
if {$status != "synth_design Complete!"} {
exit 1
}
exit 0
The launch_runs command is non-blocking, meaning that it will complete before the actual synthesis. If we try to read the status right after calling launch_run , it will be “Running”. To pause the script until the synthesis completes, we call the wait_on_run command.
Finally, we get the run status and exit 0 or 1, depending on the status message.
Tcl script for running the implementation in Vivado
The script for running Place and Route (PAR) in Vivado batch mode is similar to the synthesis script. The difference is that the run name is now “impl_1”, and that we are looking for another success message.
run_implementation.tcl :
open_proj seg7.xpr
set run_name impl_1
set cpu_count 4
reset_runs $run_name
launch_runs $run_name -jobs $cpu_count
wait_on_run $run_name
set status [get_property STATUS [get_runs $run_name]]
if {$status != "route_design Complete!"} {
exit 1
}
exit 0
Tcl script for generating the bitstream in Vivado
Finally, after if the implementation completes successfully, we can generate a bitstream for programming the FPGA. The script is similar to the previous one, but the launch_runs command is slightly different. And of course, we are looking or a different status in the end.
generate_bitstream.tcl :
open_proj seg7.xpr
set run_name impl_1
set cpu_count 4
launch_runs $run_name -to_step write_bitstream -jobs $cpu_count
wait_on_run $run_name
set status [get_property STATUS [get_runs $run_name]]
if {$status != "write_bitstream Complete!"} {
exit 1
}
exit 0
Setting up the Jenkins jobs
A job in Jenkins refers to a set of grouped software tasks. Jenkins displays jobs and their current status as items listed on the overview page. You can start jobs manually from the web interface, or they can be triggered automatically, for example, when someone pushes code to a repo, or as a result of another job completing. We will do both.
Jenkins offers several ways of managing jobs. The traditional method is the Freestyle project , where you specify every action from within the Jenkins web GUI. The more modern way of managing Jenkins jobs is to use a pipeline script that stores all of the information about the execution flow. The pipeline scripts have the benefit that you can add them to your SCM.
To create a new pipeline script, select New item from the Jenkins sidebar. In the dialog that opens, select the Pipeline option and click OK, as shown in the image below.
The first thing we have to do in the job configuration is to add the GitHub repository that contains the source code. In this example, I am using the packages repo, but the procedure is the same for all the other jobs and repos. Check the GitHub project box and enter the address in the Project url field that appears, as shown in the image below.
After that, we can set up the build triggers for this job. I want this job to start when someone pushes code to the GitHub repo. To do that, we check the box that says GitHub hook trigger for GITScm polling , as shown in the image below. Note that this will only work if you have checked the Manage hooks box in the global settings, as we did earlier.
At the bottom of the job configuration page is the Pipeline section. Here, you have to option to enter the pipeline script directly into the config page. But we want to version control the pipeline script. Therefore, we chose the Pipeline script from SCM オプション。 Make sure that Git is selected, as shown in the image below.
Paste in the URL of your GitHub repository, and select your credentials if it’s a private repo. Ours is public, so we will leave the credentials blank. We will also go with the default master branch selection.
Finally, we have to select the path to the Jenkins script within the Git repository. I have created a file named Jenkinsfile at the root of each repo. Don’t forget to click Save before you leave the page.
Jenkins pipeline scripts
Pipeline scripts follow the same syntax rules as the Apache Groovy programming language, which I must admit I had never heard of before. Nevertheless, you won’t have a hard time understanding pipeline scripts if you’ve done any kind of modern programming. At first glance, it looks like a JSON schema without the commas separating the data items.
The scripts are quite versatile, and there are many options for things like executing stages in parallel or running tasks on multiple Jenkins servers. I suggest that you take a look at the official Jenkins pipeline documentation if you want to dig deeper into the matter.
Fortunately, you don’t need to know everything about them to benefit from pipeline scripts. We will use the format below as a template for all of your scripts. We will add as many stages as we need to split the job into logical steps.
pipeline {
agent any
stages {
stage('Stage name 1') {
steps {
// Command 1
// Command 2
// Etc.
}
}
stage('Stage name 2') {
steps {
// Command 1
// Command 2
// Etc.
}
}
}
post {
failure {
emailext attachLog: true,
body: '''Project name: $PROJECT_NAME
Build number: $BUILD_NUMBER
Build Status: $BUILD_STATUS
Build URL: $BUILD_URL''',
recipientProviders: [culprits()],
subject: 'Project \'$PROJECT_NAME\' is broken'
}
}
}
If somebody pushes faulty code to the repo, we want the culprit to receive an automated email with information about the failed job. To do that, we use a failure section within a post section. This part of the script will only execute if any of the stages fail. Then, the job will stop. Jenkins won’t go to the next stage if one fails. Instead, it will jump into the failur e section. Jenkins then lifts the email addresses from the latest Git commits and sends them an email with a link to the broken build.
VHDL syntax checking job
The only repo in our design that doesn’t have a testbench is the packages repo—instead, we user our check_syntax.tcl script to verify that the code is at least valid VHDL.
In the first step of our pipeline script, we call deleteDir() 。 That’s one of the basic commands available in Jenkins pipeline scripts. It cleans the working directory by removing any leftover from previous builds.
On the next line, we call git 。 Note that this is not the git Linux command, but a command referencing the git Jenkins plugin. We tell it to clone the repository into the workspace.
Finally, on the third line of the Create project stage, we use the sh keyword to call a Linux shell command. Here, we change to the vivado directory and run the create_vivado_proj.tcl script in Vivado batch mode to recreate the Vivado project.
Jenkinsfile:
pipeline {
agent any
stages {
stage('Create project') {
steps {
deleteDir() // clean up workspace
git 'https://github.com/jonasjj/Jenkins-demo-packages'
sh 'cd vivado && vivado -mode batch -source create_vivado_proj.tcl'
}
}
stage('Check VHDL syntax') {
steps {
sh 'cd vivado && vivado -mode batch -source check_syntax.tcl'
}
}
}
post {
failure {
emailext attachLog: true,
body: '''Project name: $PROJECT_NAME
Build number: $BUILD_NUMBER
Build Status: $BUILD_STATUS
Build URL: $BUILD_URL''',
recipientProviders: [culprits()],
subject: 'Project \'$PROJECT_NAME\' is broken'
}
}
}
In the second stage, the one named Check VHDL syntax , the Vivado project already exists, so we can jump to running our Tcl script. We use the shell command again to run the check_syntax.tcl file, which will exit 0 on success, or 1 on error, causing Jenkins to mark the build as a failure.
VHDL simulation jobs
For all other jobs than the packages repo, the git one-liner command won’t work for checking out the code from GitHub. The problem is that these repos have dependencies in the form of submodules. The submodules reference other Git repositories, which the simple git command doesn’t pull by default. But that’s OK; we can fix the issue by using the more versatile checkout call, also well-documented on the Git plugin page.
Jenkinsfile;
pipeline {
agent any
stages {
stage('Create project') {
steps {
deleteDir() // clean up workspace
checkout([$class: 'GitSCM', branches: [[name: '*/master']],
doGenerateSubmoduleConfigurations: false,
extensions: [[$class: 'SubmoduleOption',
disableSubmodules: false,
parentCredentials: false,
recursiveSubmodules: true,
reference: '',
trackingSubmodules: true]],
submoduleCfg: [],
userRemoteConfigs: [[
url: 'https://github.com/jonasjj/Jenkins-demo-bcd_encoder']]])
sh 'cd vivado && vivado -mode batch -source create_vivado_proj.tcl'
}
}
stage('Run simulation') {
steps {
sh 'cd vivado && vivado -mode batch -source run_simulation.tcl'
}
}
}
post {
failure {
emailext attachLog: true,
body: '''Project name: $PROJECT_NAME
Build number: $BUILD_NUMBER
Build Status: $BUILD_STATUS
Build URL: $BUILD_URL''',
recipientProviders: [culprits()],
subject: 'Project \'$PROJECT_NAME\' is broken'
}
}
}
Finally, we run the run_simulation.tcl script in Vivado in the next stage.
The above listing shows the script used in the bcd_encoder repo. Identical scripts, only with different repo URLs, are used for the counter, digit_selector, output_mux, reset, and seg7_encoder repos as well.
FPGA implementation job
The seg7 repo contains the top module for our FPGA project. It pulls in all of the other repos as submodules. The pipeline script is similar to the one used for the simulation-only jobs, but with four added stages:Run simulation , Run implementation , Generate bitstream , and Release bitfile .
The first two stages create the project and run the simulation. I have already covered how they work in the previous sections of this article. The next three stages work the same way as the simulation stage, but with the Tcl script replaced with the ones that are relevant for the task.
Jenkinsfile:
pipeline {
agent any
stages {
stage('Create project') {
steps {
deleteDir() // clean up workspace
checkout([$class: 'GitSCM', branches: [[name: '*/master']],
doGenerateSubmoduleConfigurations: false,
extensions: [[$class: 'SubmoduleOption',
disableSubmodules: false,
parentCredentials: false,
recursiveSubmodules: true,
reference: '',
trackingSubmodules: true]],
submoduleCfg: [],
userRemoteConfigs: [[
url: 'https://github.com/jonasjj/Jenkins-demo-seg7']]])
sh 'cd vivado && vivado -mode batch -source create_vivado_proj.tcl'
}
}
stage('Run simulation') {
steps {
sh 'cd vivado && vivado -mode batch -source run_simulation.tcl'
}
}
stage('Run synthesis') {
steps {
sh 'cd vivado && vivado -mode batch -source run_synthesis.tcl'
}
}
stage('Run implementation') {
steps {
sh 'cd vivado && vivado -mode batch -source run_implementation.tcl'
}
}
stage('Generate bitstream') {
steps {
sh 'cd vivado && vivado -mode batch -source generate_bitstream.tcl'
}
}
stage('Release bitfile') {
steps {
sh '''
PROJ_NAME=seg7
RELEASE_DIR=/usr/share/nginx/html/releases/
BASE_NAME=$PROJ_NAME-`date +"%Y-%m-%d-%H-%H:%M"`
BITFILE=$BASE_NAME.bit
INFOFILE=$BASE_NAME.txt
git log -n 1 --pretty=format:"%H" >> $INFOFILE
echo -n " $PROJ_NAME " >> $INFOFILE
git describe --all >> $INFOFILE
echo "" >> $INFOFILE
echo "Submodules:" >> $INFOFILE
git submodule status >> $INFOFILE
cp $INFOFILE $RELEASE_DIR
cp vivado/seg7.runs/impl_1/top.bit $RELEASE_DIR/$BITFILE
'''
}
}
}
post {
failure {
emailext attachLog: true,
body: '''Project name: $PROJECT_NAME
Build number: $BUILD_NUMBER
Build Status: $BUILD_STATUS
Build URL: $BUILD_URL''',
recipientProviders: [culprits()],
subject: 'Project \'$PROJECT_NAME\' is broken'
}
}
}
The final stage of the implementation job is named Release bitfile 。 It contains a shell script that copies the newly generated FPGA programming file to a release folder. The shell command renames the file to include the name of the project and a timestamp.
To maintain traceability, we also generate a text file that contains the Git hash of the main repo (seg7 ) and all of the submodules. When working with Git submodules, it’s not enough to store the hash of the main repo. To generate a hash for the main repo that includes changes in all submodules, we would have to commit the main repo after pulling and updating all submodules. We don’t want to do that automatically from Jenkins.
Note that implementing the FPGA for every single push, like I am doing in the example, is probably not what you want for a real-life Jenkins project. It can take hours to build a large-scale FPGA project, and that wouldn’t work when you have a team of developers pushing multiple times per day. Instead of building after each push to the repo, you can configure Jenkins to route the FPGA only once a day. For example, at midnight, as shown by the screenshot below from the job configuration page.
Triggering builds after other jobs complete
Our example project consists of several Git repositories, but they are all tied together as Git submodules. Except for packages, all the other repos depend on at least one other repository. Most depend on the packages repository. Have a look at the dependency graph that I presented earlier in this article to see how it all fits together.
Therefore, we should trigger jobs not only by pushes to the repo in question but also after any of the submodules are touched. We can achieve this in Jenkins by visiting every job and setting the Build after other projects are built option accordingly.
The image below shows the trigger for the bcd_encoder project. It will start after the packages repo, which it depends on, completes a build successfully.
The top module depends on all other repos. I have added them as watch projects in a comma-separated list, as shown in the image below. Note that you may not want to do this for the FPGA implementation job if it takes a long time to route, as I mentioned in the previous section.
Serving the bitfiles using Nginx
Since we already have a web server running, we can use if for serving the release files over HTTP. I want all new bitfiles to appear on the URL jenkins.vhdlwhiz.com/releases 。 Let’s see how we can use Nginx for this.
Our implementation job already copies new bitfiles to a directory on the Nginx HTML root, but we haven’t created it yet. Create the release dir and give the Jenkins user write permissions by issuing the following commands:
mkdir /usr/share/nginx/html/releases/ chown jenkins.root /usr/share/nginx/html/releases/
Then we have to make a change to the /etc/nginx/nginx.conf file. Find the server section in the config file with a name equal to your domain. Add the following location section inside of it, directly below the root (‘/’) location section:
location ^~ /releases {
alias /usr/share/nginx/html/releases/;
autoindex on;
}
Finally, after you have saved the file, test the configuration file, and reload the Nginx server:
nginx -t systemctl reload nginx
If everything worked, you should be able to list the content of the release directory, as shown in the screenshot below from Google Chrome.
To tie the Jenkins web interface to the release dir, I want to create a link to if from the Jenkins sidebar. We have already installed the Sidebar Link plugin that enables custom links in the sidebar.
The next step is to go to Manage Jenkins->Configure System and scroll down to the Additional Sidebar Links section. Here, we can specify the name and URL of the new link, as shown in the image below. The link icon field is optional. I reused one of the icons that came with the Jenkins server.
After completing the previous step, you should now have a custom link to the bitfile releases in the sidebar, complete with a nice-looking folder icon, as you can see from the image below.
概要
Jenkins can be a valuable tool also for FPGA teams. Automating tasks can save your company time and improve the quality of your code. By using automatic build triggers and automated job pipelines, fewer coding errors will go unnoticed.
As we have seen from the example project presented in this article, Jenkins can implement a complete suite of regression tests for your VHDL code. It shows the current health of your project in a pleasant graphical web interface, suitable for even the most VHDL-illiterate project manager.
If you wish to try out Jenkins for FPGA development, I recommend following the steps in this article on an UpCloud VPS instance. I thoroughly researched all VPS providers a few years ago before moving VHDLwhiz to a VPS. I found that UpCloud was the fastest and best alternative. I’m still 100% pleased with the service.
If you decide to open an account on UpCloud, I kindly ask that you use my referral link or code:NV78V6 。 Not only do you support VHDLwhiz, but you also get $25 of credit on UpCloud when using the promo code.
VHDL