1.起源
前回の記事では、ヘッダーファイルのクロスプラットフォームを共有しました。これは、プラットフォーム下のWindows用のこのヘッダーファイルがより意味のあるものに成長することです。これは、インポートおよびエクスポート宣言ライブラリ関数(dllexport、dllimport)を処理するためです。
実際、このヘッダーファイルに基づいて拡張を続け、よりきめ細かい制御を実現できます。例:コンパイラーの判断、コンパイラーのバージョンの判断など。
同様に、ソースコードでいくつかのクロスプラットフォームの問題が発生します。異なるプラットフォームでの異なる機能、実装は同じではありません、これらのプラットフォーム固有のコードを編成する方法は?この記事では、この問題について説明します。
PS:記事の最後に、単純なクロスプラットフォームのビルドコード例を示します。
2.問題の紹介
ライブラリを作成し、関数を実装する必要があるとします。システムのタイムスタンプを取得します。実装ライブラリの作成者として、次のAPI関数を提供することにしました。
t_time.h:インターフェース関数の宣言(t_get_timestamp);
t_time.c:インターフェース関数の実装;
次のタスクは、関数実装のさまざまなCライブラリまたはシステムコールを介してシステムの現在のタイムスタンプを計算することです。
以下の下のLinuxプラットフォームでは、以下のコードによって達成することができます。
struct timeval tv;
gettimeofday(&tv, null);
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
以下の下でのWindowsプラットフォームで、これは以下のコードによって達成することができます。
struct timeb tp;
ftime(&tp);
return tp.time *1000 + tp.millitm;
したがって、問題は、これら2つのプラットフォーム関連コードをどのようにまとめるかということです。組織化の方法は3つあります。良いことも悪いことも違いはありません。習慣は人それぞれです。自分とチームに合った方法を選択するだけです。
また、この例では関数が1つしかなく、比較的短いです。このようなクロスプラットフォーム機能が多く、非常に長い場合は、選択が異なる場合があります。
3、3つのソリューション
プラン1
インターフェース関数で直接、プラットフォームマクロ定義を介して異なるプラットフォームを区別します。
プラットフォームマクロ定義(T_LINUX、T_WINDOWS)は前の記事で紹介されました。オペレーティングシステムとコンパイラを使用して現在のプラットフォームを決定し、次に統合プラットフォームマクロ定義を定義して独自に使用します。
コードは次のように構成されています。
int64 t_get_timestamp()
{
int64 ts = -1;
#if defined(T_LINUX)
struct timeval tv;
gettimeofday(&tv, null);
ts = tv.tv_sec * 1000 + tv.tv_usec / 1000;
#elif defined(T_WINDOWS)
struct timeb tp;
ftime(&tp);
ts = tp.time;
ts = ts *1000 + tp.millitm;
#endif
return ts;
}
このように、すべてのプラットフォームコードはAPI関数に配置され、条件付きコンパイルはプラットフォームマクロ定義を介して実行されます。これは、コードが比較的短く、見栄えがよいためです。
シナリオ2
さまざまなプラットフォームの実装コードを別々のファイルに入れてから、#include前処理シンボルを使用して、API関数にプラットフォーム関連のコードを導入します。
つまり、さらに2つのファイルを追加します。
t_time_linux.c:Linuxプラットフォームで
コード実装を保存します。t_time_windows.c:Windowsプラットフォームでコード実装を保存します。
(1)t_time_linux.c
#include "t_time.h"
#include <sys/time.h>
int64 t_get_timestamp()
{
int64 ts = -1;
struct timeval tv;
gettimeofday(&tv, null);
ts = tv.tv_sec * 1000 + tv.tv_usec / 1000;
return ts;
}
(2)t_time_windows.c
#include "t_time.h"
#include <windows.h>
#include <sys/timeb.h>
int64 t_get_timestamp()
{
int64 ts = -1;
struct timeb tp;
ftime(&tp);
ts = tp.time;
ts = ts *1000 + tp.millitm;
return ts;
}
(3)t_time.c
このファイルは何もしません。他のコードが含まれているだけです。
#include "t_time.h"
#if defined(T_LINUX)
#include <t_time_linux.c>
#elif defined(T_WINDOWS)
#include <t_time_windows.c>
#else
int64 t_get_timestamp()
{
return -1;
}
#endif
この種の組織にうんざりしている人もいます。通常は.hヘッダーファイルをインクルードすることですが、ここにさまざまな.cソースファイルをインクルードするプラットフォームマクロ定義があります。奇妙に感じますか?!
実際、これを行うオープンソースライブラリには、次のようなものがあります。
スキーム3
上記のスキーム2では、ソースコードはさまざまなプラットフォームの実装コードで埋められています。
実際、考え方を変えることができます。プラットフォームごとに異なるファイルに配置されたので、コンパイルプロセスに異なるソースファイルを追加できます。
テストコードはcmakeツールを使用して作成されるため、CMakelists.txtファイルを編集して、コンパイルに関係するソースファイルを制御できます。
CMakelists.txtファイルの一部
# 设置平台变量
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
set(PLATFORM linux)
elseif (CMAKE_SYSTEM_NAME MATCHES "Windows")
set(PLATFORM windows)
endif()
# 根据平台变量,来编译不同的源文件
set(LIBSRC t_time_${PLATFORM}.c)
この種の編成により、コードがより「クリーン」になります。同様に、いくつかのオープンソースライブラリが同じことをしていることもわかります。
四、もう一つのこと
記事の長さについては、上記は投稿されたコードのほんの一部です。
私は、cmakeを使用してクロスプラットフォームのダイナミックライブラリ、静的ライブラリ、および実行可能プログラムを構築する、最も単純なデモの1つを作成しました。このデモを書く目的は、主に記事を書くときにいくつかのコードをテストするためのシェルとしてです。
下では、Linuxプラットフォーム、手動でcmakeの命令によってコンパイル、下のWindowsプラットフォームで、次のことができ、直接コンパイルして実行してCLion統合開発環境、またはあなたが直接生成することができますVS2017 / 2019のソリューションをcmakeのツールを使用して。
このデモは、小さなパートナーのためにすでにgiteeウェアハウスに配置されています。公開番号にメッセージを残してください:dg36、クローンアドレスを受け取ることができます。
1. C言語のポインター-最下位の原則から高度なスキルまで、グラフィックとコードを使用して完全に説明します
2.元のgdbの最下位のデバッグの原則は非常に単純です
3.ステップバイステップの分析-Cの使用方法オブジェクト指向プログラミングを実装する
4.すべてのことソフトウェアアーキテクチャを階層化してモジュールに分割する必要があり、具体的に何を行う必要があるか(1)
5。ソフトウェアアーキテクチャを階層化してモジュールに分割する必要があると言われています。具体的に行う必要があります(2)