ソフトウェアライブラリは、コードを再利用するための長年の、簡単で、賢明な方法です。この記事では、ライブラリを最初から作成してクライアントが利用できるようにする方法について説明します。 2つのサンプルライブラリはLinuxを対象としていますが、これらのライブラリを作成、公開、および使用する手順は、他のUnixライクなシステムにも適用されます。
サンプルライブラリはCで記述されており、タスクに適しています。 Linuxカーネルは、ほとんどがCで記述されており、残りはアセンブリ言語で記述されています。 (同じことが、macOSなどのWindowsおよびLinuxのいとこにも当てはまります。)入出力、ネットワーキング、文字列処理、数学、セキュリティ、データエンコーディングなどの標準システムライブラリは、同様に主にCで記述されます。したがって、CはLinuxのネイティブ言語で記述します。さらに、Cは高級言語間のパフォーマンスの基準を設定します。
その他のLinuxリソース
- Linuxコマンドのチートシート
- 高度なLinuxコマンドのチートシート
- 無料のオンラインコース:RHELの技術概要
- Linuxネットワーキングのチートシート
- SELinuxチートシート
- Linuxの一般的なコマンドのチートシート
- Linuxコンテナとは何ですか?
- 最新のLinux記事
ライブラリにアクセスするための2つのサンプルクライアント(1つはC、もう1つはPython)もあります。 CクライアントがCで記述されたライブラリにアクセスできるのは当然ですが、Pythonクライアントは、Cで記述されたライブラリが他の言語のクライアントにサービスを提供できることを示しています。
Linuxシステムには2種類のライブラリがあります:
- 静的ライブラリ(別名ライブラリアーカイブ) コンパイルプロセスのリンクフェーズ中に、静的にコンパイルされたクライアント(CまたはRustのクライアントなど)にベイクされます。実際には、各クライアントはライブラリの独自のコピーを取得します。各ライブラリクライアントを静的ライブラリに再リンクする必要があるため、ライブラリを修正する必要がある場合(たとえば、バグを修正するため)、静的ライブラリの重大な欠点が浮き彫りになります。次に説明するダイナミックライブラリは、この欠点を回避します。
- 動的(別名共有)ライブラリ 静的にコンパイルされたクライアントプログラムのリンクフェーズ中にフラグが立てられますが、それ以外の場合、クライアントプログラムとライブラリコードは実行時まで接続されません。ライブラリコードはクライアントにベイクされません。実行時に、システムのダイナミックローダーは、クライアントがCなどの静的にコンパイルされた言語であるか、Pythonなどの動的にコンパイルされた言語であるかに関係なく、共有ライブラリを実行中のクライアントに接続します。その結果、クライアントに迷惑をかけることなくダイナミックライブラリを更新できます。最後に、複数のクライアントがダイナミックライブラリの単一のコピーを共有できます。
一般に、動的ライブラリは静的ライブラリよりも優先されますが、複雑さとパフォーマンスにはコストがかかります。各ライブラリタイプが作成および公開される方法は次のとおりです。
- ライブラリのソースコードは、1つ以上のオブジェクトモジュールにコンパイルされます。これらのオブジェクトモジュールは、ライブラリに含めて実行可能クライアントにリンクできるバイナリファイルです。
- オブジェクトモジュールは単一のファイルにパッケージ化されています。静的ライブラリの場合、標準の拡張子は
.a
です。 「アーカイブ」のために。ダイナミックライブラリの場合、拡張子は.so
です。 「共有オブジェクト」の場合。同じ機能を持つ2つのサンプルライブラリは、ファイルlibprimes.a
として公開されています。 (静的)およびlibshprimes.so
(動的)。プレフィックスlib
両方のタイプのライブラリに使用されます。 - ライブラリファイルは標準ディレクトリにコピーされるため、クライアントプログラムは大騒ぎせずにライブラリにアクセスできます。ライブラリの一般的な場所は、静的か動的かに関係なく、
/ usr / lib
です。 または/usr / local / lib
;他の場所も可能です。
各タイプのライブラリを構築および公開するための詳細な手順は、まもなく公開されます。ただし、最初に、2つのライブラリのC関数を紹介します。
2つのサンプルライブラリは、同じ5つのC関数から構築されており、そのうちの4つはクライアントプログラムからアクセスできます。他の4つのうちの1つのユーティリティである5番目の関数は、Cが情報の非表示をどのようにサポートするかを示しています。各関数のソースコードは十分に短いため、関数を1つのソースファイルに格納できますが、複数のソースファイル(たとえば、公開されている4つの関数ごとに1つ)はオプションです。
ライブラリ関数は基本的なものであり、さまざまな方法で素数を処理します。すべての関数は、引数として符号なし(つまり、非負)の整数値を期待します:
-
is_prime
関数は、その単一の引数が素数であるかどうかをテストします。 -
are_coprimes
関数は、その2つの引数の最大公約数(gcd)が1であるかどうかをチェックします。これは、コプライムを定義します。 -
prime_factors
関数は、その引数の素因数をリストします。 ゴールドバッハコード> 関数は、4以上の偶数の整数値を想定し、この引数に合計される2つの素数をリストします。複数の合計ペアが存在する場合があります。この関数の名前は、18世紀の数学者Christian Goldbachにちなんで名付けられました。彼の推測では、2より大きい整数はすべて、2つの素数の合計であり、数論で最も古い未解決の問題の1つです。
ユーティリティ関数gcd
デプロイされたライブラリファイルに存在しますが、この関数は、含まれているファイルの外部からはアクセスできません。したがって、ライブラリクライアントは gcd
を直接呼び出すことはできません。 働き。 C関数を詳しく見ると、要点が明確になります。
C関数の詳細
Cのすべての関数には、関数のスコープを決定するストレージクラスがあります。関数には2つのオプションがあります:
- 関数のデフォルトのストレージクラスは
extern
です 、関数にグローバルスコープを与えます。クライアントプログラムは、任意のextern
を呼び出すことができます サンプルライブラリの関数。関数are_coprimes
の定義は次のとおりです。 明示的なextern
:
extern unsigned are_coprimes(unsigned n1, unsigned n2) {
...
} - ストレージクラス
static
関数のスコープを、関数が定義されているファイルに制限します。サンプルライブラリでは、ユーティリティ関数gcd
static
です :
static unsigned gcd(unsigned n1, unsigned n2) {
...
}
primes.c
内でのみ機能します ファイルはgcd
を呼び出すことができます 、および関数 are_coprimes
のみ そうします。静的ライブラリと動的ライブラリが構築および公開されると、他のプログラムが extern
を呼び出すことができます。 are_coprimes
などの関数 ただし、 static
ではありません 関数gcd
。 static
したがって、ストレージクラスは gcd
を非表示にします 関数のスコープを他のライブラリ関数に制限することにより、ライブラリクライアントから関数を作成します。
gcd
以外の機能 primes.c
内 ファイルはストレージクラスを指定する必要はありません。デフォルトではextern
になります。 。ただし、ライブラリでは extern
を作成するのが一般的です。 明示的。
Cは、関数の定義と宣言を区別します。これは、ライブラリにとって重要です。定義から始めましょう。 Cには名前付き関数のみがあり、すべての関数は次のように定義されています:
- 一意の名前。プログラム内の2つの関数に同じ名前を付けることはできません。
- 引数リスト。空の場合があります。引数が入力されます。
- 戻り値のタイプ(例:
int
) 32ビット符号付き整数の場合)またはvoid
値が返されない場合。 - 中括弧で囲まれた本体。不自然な例では、本体が空である可能性があります。
プログラム内のすべての関数は、1回だけ定義する必要があります。
ライブラリ関数are_coprimes
の完全な定義は次のとおりです。 :
extern unsigned are_coprimes(unsigned n1, unsigned n2) { /* definition */
return 1 == gcd(n1, n2); /* greatest common divisor of 1? */
}
この関数は、2つの整数引数の最大公約数が1であるかどうかに応じて、ブール値(falseの場合は0、trueの場合は1)を返します。ユーティリティ関数 gcd
整数引数の最大公約数n1
を計算します およびn2
。
定義とは異なり、関数宣言には本文がありません:
extern unsigned are_coprimes(unsigned n1, unsigned n2); /* declaration */
宣言は、引数リストの後にセミコロンで終わります。体を囲む中括弧はありません。関数は、プログラム内で複数回宣言される場合があります。
なぜ宣言が必要なのですか? Cでは、呼び出された関数はその呼び出し元に表示される必要があります。コンパイラーの煩わしさに応じて、このような可視性を提供するさまざまな方法があります。確実な方法の1つは、両方が同じファイルに存在する場合に、呼び出し元の上に呼び出された関数を定義することです。
void f() {...} /* f is defined before being called */
void g() { f(); } /* ok */
関数f
の定義 関数g
からの呼び出しの下に移動できます f
の場合 呼び出しの上で宣言されました:
void f(); /* declaration makes f visible to caller */
void g() { f(); } /* ok */
void f() {...} /* easier to put this above the call from g */
しかし、呼び出された関数がその呼び出し元とは異なるファイルにある場合はどうなるでしょうか。各関数をプログラムで1回だけ定義する必要がある場合、あるファイルで定義された関数を別のファイルでどのように表示できますか?
この問題は、静的か動的かに関係なく、ライブラリに影響します。たとえば、2つの素数ライブラリの関数は、ソースファイル primes.c
で定義されています。 、そのバイナリコピーは各ライブラリにあります。ただし、これらの定義された関数は、独自のソースファイルを持つ別個のプログラムであるCのライブラリクライアントに表示される必要があります。
ファイル全体の可視性を提供することは、関数宣言が実行できることです。 「primes」の例では、 primes.h
という名前のヘッダーファイルがあります。 これは、Cのライブラリクライアントに表示される4つの関数を宣言します:
/** header file primes.h: function declarations **/
extern unsigned is_prime(unsigned);
extern void prime_factors(unsigned);
extern unsigned are_coprimes(unsigned, unsigned);
extern void goldbach(unsigned);
これらの宣言は、各関数の呼び出し構文を指定することにより、インターフェースとして機能します。
クライアントの便宜のために、テキストファイル primes.h
Cコンパイラの検索パス上のディレクトリに保存できます。一般的な場所は/usr / include
です。 および/usr / local / include
。 Cクライアントは#include
このヘッダーファイルは、クライアントのソースコードの先頭近くにあります。 (したがって、ヘッダーファイルは別のソースファイルの「ヘッド」にインポートされます。)Cヘッダーファイルは、ユーティリティ(Rustの bindgen
など)への入力としても機能します。 )他の言語のクライアントがCライブラリにアクセスできるようにします。
要約すると、ライブラリ関数は1回だけ定義されますが、必要に応じて宣言されます。 Cのライブラリクライアントには宣言が必要です。ヘッダーファイルには関数宣言が含まれている必要がありますが、関数定義は含まれていません。ヘッダーファイルに定義が含まれている場合、そのファイルはCプログラムに複数回インクルードされる可能性があるため、Cプログラムで関数を1回だけ定義する必要があるという規則に違反します。
以下は2つのライブラリのソースコードです。このコード、ヘッダーファイル、および2つのサンプルクライアントは、私のWebサイトで入手できます。
ライブラリ機能
#include <stdio.h>
#include <math.h>
extern unsigned is_prime(unsigned n) {
if (n <= 3) return n > 1; /* 2 and 3 are prime */
if (0 == (n % 2) || 0 == (n % 3)) return 0; /* multiples of 2 or 3 aren't */
/* check that n is not a multiple of other values < n */
unsigned i;
for (i = 5; (i * i) <= n; i += 6)
if (0 == (n % i) || 0 == (n % (i + 2))) return 0; /* not prime */
return 1; /* a prime other than 2 or 3 */
}
extern void prime_factors(unsigned n) {
/* list 2s in n's prime factorization */
while (0 == (n % 2)) {
printf("%i ", 2);
n /= 2;
}
/* 2s are done, the divisor is now odd */
unsigned i;
for (i = 3; i <= sqrt(n); i += 2) {
while (0 == (n % i)) {
printf("%i ", i);
n /= i;
}
}
/* one more prime factor? */
if (n > 2) printf("%i", n);
}
/* utility function: greatest common divisor */
static unsigned gcd(unsigned n1, unsigned n2) {
while (n1 != 0) {
unsigned n3 = n1;
n1 = n2 % n1;
n2 = n3;
}
return n2;
}
extern unsigned are_coprimes(unsigned n1, unsigned n2) {
return 1 == gcd(n1, n2);
}
extern void goldbach(unsigned n) {
/* input errors */
if ((n <= 2) || ((n & 0x01) > 0)) {
printf("Number must be > 2 and even: %i is not.\n", n);
return;
}
/* two simple cases: 4 and 6 */
if ((4 == n) || (6 == n)) {
printf("%i = %i + %i\n", n, n / 2, n / 2);
return;
}
/* for n >= 8: multiple possibilities for many */
unsigned i;
for (i = 3; i < (n / 2); i++) {
if (is_prime(i) && is_prime(n - i)) {
printf("%i = %i + %i\n", n, i, n - i);
/* if one pair is enough, replace this with break */
}
}
}
これらの機能は、ライブラリミルの要点として機能します。 2つのライブラリは、まったく同じソースコードと、ヘッダーファイル primes.h
から派生しています。 は両方のライブラリのCインターフェイスです。
静的ライブラリと動的ライブラリを構築および公開する手順は、いくつかの詳細が異なります。静的ライブラリには3つの手順のみが必要であり、動的ライブラリにはさらに2つの手順が必要です。ダイナミックライブラリを構築するための追加の手順は、ダイナミックアプローチの追加された柔軟性を反映しています。静的ライブラリから始めましょう。
ライブラリソースファイルprimes.c
オブジェクトモジュールにコンパイルされます。これがコマンドで、パーセント記号がシステムプロンプトになっています(二重の鋭い記号が私のコメントを紹介しています):
% gcc -c primes.c ## step 1 static
これにより、バイナリファイル primes.o
が生成されます 、オブジェクトモジュール。フラグ-c
コンパイルのみを意味します。
次のステップは、Linux ar
を使用してオブジェクトモジュールをアーカイブすることです。 ユーティリティ:
% ar -cvq libprimes.a primes.o ## step 2 static
3つのフラグ-cvq
「create」、「verbose」、「quickappend」の略です(新しいファイルをアーカイブに追加する必要がある場合)。プレフィックスlib
を思い出してください は標準ですが、ライブラリ名は任意です。もちろん、ライブラリのファイル名は、競合を避けるために一意である必要があります。
アーカイブを公開する準備ができました:
% sudo cp libprimes.a /usr/local/lib ## step 3 static
静的ライブラリはクライアントがアクセスできるようになりました。その例は近日公開されます。 ( sudo
ファイルを/usr / local / lib
にコピーするための正しいアクセス権を確保するために含まれています 。)
ダイナミックライブラリには、パッケージ化のために1つ以上のオブジェクトモジュールも必要です。
% gcc primes.c -c -fpic ## step 1 dynamic
追加されたフラグ-fpic
位置に依存しないコードを生成するようにコンパイラーに指示します。これは、固定メモリー位置にロードする必要のないバイナリ・モジュールです。このような柔軟性は、複数のダイナミックライブラリのシステムで重要です。結果のオブジェクトモジュールは、静的ライブラリ用に生成されたものよりもわずかに大きくなります。
オブジェクトモジュールから単一のライブラリファイルを作成するコマンドは次のとおりです。
% gcc -shared -Wl,-soname,libshprimes.so -o libshprimes.so.1 primes.o ## step 2 dynamic
フラグ-shared
ライブラリが静的ではなく共有(動的)であることを示します。 -Wl
flagは、コンパイラオプションのリストを導入します。最初のオプションは、ダイナミックライブラリの soname
を設定します。 、必須です。 soname
最初にライブラリの論理名を指定します( libshprimes.so
)次に、 -o
の後に続きます フラグ、ライブラリの物理ファイル名( libshprimes.so.1
)。目的は、物理ファイル名を新しいバージョンで変更できるようにしながら、論理名を一定に保つことです。この例では、物理ファイル名の末尾にある1 libshprimes.so.1
ライブラリの最初のバージョンを表します。論理ファイル名と物理ファイル名は同じでもかまいませんが、ベストプラクティスは別々の名前にすることです。クライアントは、論理名(この場合は libshprimes.so
)を介してライブラリにアクセスします )、後で明確にします。
次のステップは、共有ライブラリを適切なディレクトリにコピーして、クライアントが簡単にアクセスできるようにすることです。たとえば、 / usr / local / lib again:
% sudo cp libshprimes.so.1 /usr/local/lib ## step 3 dynamic
これで、共有ライブラリの論理名( libshprimes.so
)の間にシンボリックリンクが設定されました。 )とその完全な物理ファイル名( /usr/local/lib/libshprimes.so.1
)。 / usr / local / lib
を使用してコマンドを実行するのが最も簡単です。 作業ディレクトリとして:
% sudo ln --symbolic libshprimes.so.1 libshprimes.so ## step 4 dynamic
論理名libshprimes.so
変更する必要はありませんが、シンボリックリンクのターゲット( libshrimes.so.1
)バグを修正したり、パフォーマンスを向上させたりする新しいライブラリの実装については、必要に応じて更新できます。
最後のステップ(予防措置)は、 ldconfig
を呼び出すことです。 システムの動的ローダーを構成するユーティリティ。この構成により、ローダーは新しく公開されたライブラリを確実に見つけることができます。
% sudo ldconfig ## step 5 dynamic
これで、ダイナミックライブラリは、次の2つのサンプルライブラリを含め、クライアントで使用できるようになりました。
Cライブラリクライアント
サンプルCクライアントはプログラムテスターであり、そのソースコードは2つの #include
で始まります。 ディレクティブ:
#include <stdio.h> /* standard input/output functions */
#include <primes.h> /* my library functions */
ファイル名を囲む山かっこは、これらのヘッダーファイルがコンパイラの検索パス( primes.h
の場合)で見つかることを示します。 、ディレクトリ / usr / local / include
)。この#include
がないと 、コンパイラは、 is_prime
などの関数の宣言が欠落していることについて文句を言います。 およびprime_factors
、両方のライブラリで公開されています。ちなみに、テスタープログラムのソースコードは、2つのライブラリのそれぞれをテストするためにまったく変更する必要はありません。
対照的に、ライブラリのソースファイル( primes.c
)これらの #include
で開きます ディレクティブ:
#include <stdio.h>
#include <math.h>
ヘッダーファイルmath.h
ライブラリ関数prime_factors
が必要なため、 数学関数sqrt
を呼び出します 標準ライブラリlibm.so
。
参考までに、テスタープログラムのソースコードは次のとおりです。
テスタープログラム
#include <stdio.h>
#include <primes.h>
int main() {
/* is_prime */
printf("\nis_prime\n");
unsigned i, count = 0, n = 1000;
for (i = 1; i <= n; i++) {
if (is_prime(i)) {
count++;
if (1 == (i % 100)) printf("Sample prime ending in 1: %i\n", i);
}
}
printf("%i primes in range of 1 to a thousand.\n", count);
/* prime_factors */
printf("\nprime_factors\n");
printf("prime factors of 12: ");
prime_factors(12);
printf("\n");
printf("prime factors of 13: ");
prime_factors(13);
printf("\n");
printf("prime factors of 876,512,779: ");
prime_factors(876512779);
printf("\n");
/* are_coprimes */
printf("\nare_coprime\n");
printf("Are %i and %i coprime? %s\n",
21, 22, are_coprimes(21, 22) ? "yes" : "no");
printf("Are %i and %i coprime? %s\n",
21, 24, are_coprimes(21, 24) ? "yes" : "no");
/* goldbach */
printf("\ngoldbach\n");
goldbach(11); /* error */
goldbach(4); /* small one */
goldbach(6); /* another */
for (i = 100; i <= 150; i += 2) goldbach(i);
return 0;
}
tester.c
のコンパイル時 実行可能ファイルの場合、注意が必要なのはリンクフラグの順序です。 2つのサンプルライブラリがプレフィックスlib
で始まることを思い出してください。 、それぞれに通常の拡張子が付いています: .a
静的ライブラリlibprimes.a
の場合 および.so
ダイナミックライブラリlibshprimes.so
の場合 。リンク仕様では、プレフィックス lib
そして拡張機能は失われます。リンクフラグは-l
で始まります (小文字のL)、およびコンパイルコマンドには多くのリンクフラグが含まれる場合があります。例としてダイナミックライブラリを使用した、テスタープログラムの完全なコンパイルコマンドは次のとおりです。
% gcc -o tester tester.c -lshprimes -lm
最初のリンクフラグは、ライブラリ libshprimes.so
を識別します 2番目のリンクフラグは、標準の数学ライブラリ libm.so
を識別します。 。
リンカはレイジーです。つまり、リンクフラグの順序が重要です。たとえば、リンク仕様の順序を逆にすると、コンパイル時エラーが発生します。
% gcc -o tester tester.c -lm -lshprimes ## danger!
libm.so
にリンクするフラグ 最初に来ますが、このライブラリの関数はテスタープログラムで明示的に呼び出されません。したがって、リンカは math.so
にリンクしません。 図書館。 sqrt
の呼び出し ライブラリ関数は、 prime_factors
でのみ発生します 現在libshprimes.so
に含まれている関数 図書館。テスタープログラムのコンパイルで発生するエラーは次のとおりです。
primes.c: undefined reference to 'sqrt'
したがって、リンクフラグの順序は、 sqrt
であることをリンカに通知する必要があります。 機能が必要です:
% gcc -o tester tester.c -lshprimes -lm ## -lshprimes 1st
リンカは、ライブラリ関数 sqrt
への呼び出しを取得します libshprimes.so
にあります ライブラリ、したがって、数学ライブラリ libm.so
への適切なリンクを実行します 。リンクフラグの順序をサポートする、より複雑なリンクオプションがあります。ただし、この場合、簡単な方法はリンクフラグを適切に配置することです。
テスタークライアントの実行からの出力は次のとおりです。
is_prime
Sample prime ending in 1: 101
Sample prime ending in 1: 401
...
168 primes in range of 1 to a thousand.
prime_factors
prime factors of 12: 2 2 3
prime factors of 13: 13
prime factors of 876,512,779: 211 4154089
are_coprime
Are 21 and 22 coprime? yes
Are 21 and 24 coprime? no
goldbach
Number must be > 2 and even: 11 is not.
4 = 2 + 2
6 = 3 + 3
...
32 = 3 + 29
32 = 13 + 19
...
100 = 3 + 97
100 = 11 + 89
...
goldbach
の場合 関数では、比較的小さい偶数値(18など)でも、合計する素数のペアが複数ある場合があります(この場合、5+13と7+11)。このような複数の素数のペアは、ゴールドバッハの予想の証明の試みを複雑にする要因の1つです。
Pythonクライアントでのまとめ
Pythonは、Cとは異なり、静的にコンパイルされた言語ではありません。つまり、サンプルのPythonクライアントは、静的バージョンではなく動的バージョンの素数ライブラリにアクセスする必要があります。そのために、Pythonには、ある言語で記述されたプログラムが別の言語で記述された関数を呼び出すことができる外部関数インターフェイス(FFI)をサポートするさまざまなモジュール(標準およびサードパーティ)があります。 Python ctypes
は、PythonコードがC関数を呼び出すことを可能にする標準的で比較的単純なFFIです。
インターフェース言語がまったく同じデータ型を持つ可能性は低いため、FFIには課題があります。たとえば、素数ライブラリはCタイプの unsigned int
を使用します 、Pythonにはありません。 ctypes
FFIはCのunsignedint
をマップします Python int
に 。 4つのextern
のうち 素数ライブラリで公開されているC関数。2つは明示的なctypes
を使用してPythonでより適切に動作します。 構成。
C関数prime_factors
およびgoldbach
void
があります 戻り型ではなく、 ctypes
デフォルトでは、Cの void
を置き換えます Python int
を使用 。 Pythonコードから呼び出されると、2つのC関数はスタックからランダムな(したがって意味のない)整数値を返します。ただし、 ctypes
関数がNone
を返すように構成できます (Pythonのnullタイプ)代わりに。 prime_factors
の構成は次のとおりです 機能:
primes.prime_factors.restype = None
同様のステートメントがgoldbach
を処理します 機能。
以下のインタラクティブセッション(Python 3)は、Pythonクライアントと素数ライブラリ間のインターフェイスが単純であることを示しています。
>>> from ctypes import cdll
>>> primes = cdll.LoadLibrary("libshprimes.so") ## logical name
>>> primes.is_prime(13)
1
>>> primes.is_prime(12)
0
>>> primes.are_coprimes(8, 24)
0
>>> primes.are_coprimes(8, 25)
1
>>> primes.prime_factors.restype = None
>>> primes.goldbach.restype = None
>>> primes.prime_factors(72)
2 2 2 3 3
>>> primes.goldbach(32)
32 = 3 + 29
32 = 13 + 19
素数ライブラリの関数は、単純なデータ型 unsigned int
のみを使用します。 。このCライブラリが構造などの複雑な型を使用し、構造へのポインタがライブラリ関数との間で受け渡されたり返されたりした場合、FFIは ctypes
よりも強力です。 PythonとCの間のスムーズなインターフェースには、より良いかもしれません。それでも、 ctypes
例は、PythonクライアントがCで記述されたライブラリを使用できることを示しています。実際、科学計算用の人気のあるNumPyライブラリはCで記述され、高レベルのPythonAPIで公開されています。
単純な素数ライブラリと高度なNumPyライブラリは、Cがプログラミング言語の共通語であり続けることを強調しています。ほとんどすべての言語がCと通信でき、Cを介して、Cと通信する他の言語と通信できます。PythonはCと簡単に通信できます。別の例として、ProjectPanamaがJavaNative Interface(JNI 。