1. 程式人生 > >Ubuntu系統下通過Clang編譯器編寫Objective-C

Ubuntu系統下通過Clang編譯器編寫Objective-C

Objective-C作為Apple的first-class程式語言,在很長一段時間內都得到大量開發者的追捧。其中,Objective-C對C語言的完全相容、靈活性以及OOP特性,使得它成為一門十分優秀,且平衡度很高的程式語言。在我所有用過的程式語言中,Objective-C是最最適合用於開發驅動以及應用層程式的程式語言,它比C++輕便地多,但功能上又比C++更強;而在完美相容C語言的基礎上增加了教科書般的OOP特性!其中,訊息機制是其靈魂。

為了能夠在其他平臺上較好地使用現代化的Objective-C,我這裡推薦使用LLVM Clang編譯工具鏈。另外,以下描述的安裝過程是在Ubuntu16.04下進行的,而更早版本的Ubuntu系統也差不多可按照以下操作步驟完成安裝和編譯使用。

我們裝好Ubuntu系統之後,GCC及其相關執行時庫就已經預設安裝在系統中了。為了保證我們當前用使用最新的Objective-C編譯器以及Foundation庫,我們按照以下步驟先安裝GNUStep庫:

1、sudo apt-get install gnustep

2、sudo apt-get install gnustep-devel

這樣我們把Objective-C的GNUStep執行時庫都安裝好了。

下面我們開始下載並安裝最新release的LLVM Clang:

1、sudo apt-get install llvm

2、sudo apt-get install clang

完成這些安裝之後,我們可以把Clang中Apple所給予的Blocks語法相關的執行時庫以及Apple開源的Grand Central Dispatch庫給裝上。

1、sudo apt-get install libblocksruntime-dev

2、sudo apt-get install libdispatch-dev

這樣,編譯器以及必要的執行時庫的安裝都結束了。使用Ubuntu系統的一大好處就是安裝一些常規工具非常便利,只需要一個sudo apt-get install就能搞定。所以它比較適合非深度Linux使用者進行開發使用。

由於Objective-C所依賴的編譯選項以及執行時庫比較多。所以我這裡建議各位做一個makefile或是像我在下面描述的寫一個shell檔案,把需要的編譯命令選項放進去。這樣我們後面要編譯原始檔時就會方便很多。

我們首先通過執行以下命令來觀察Objective-C編譯時所需要的編譯選項:

gnustep-config --objc-flags

然後我們把輸出的內容先複製到shell檔案中儲存好。再執行以下命令檢視Objective-C連線時所需要的載入選項:

gnustep-config --objc-libs

然後我們把載入選項複製黏貼到我們的shell檔案中。

下面我們可以建立一個main.m原始檔進行測試:

#include <dispatch/dispatch.h>
#include <Block.h>
#include <stdio.h>
#include <stdbool.h>

#import <Foundation/Foundation.h>


static int (^BlockTest(void))(int)
{
    __block int a = 10;

    int (^block)(int) = ^int(int i) {
            a += i;
            return a;
        };

    block(100);

    printf("The value is: %d\n", a);

    return Block_copy(block);
}

@interface DummyObject: NSObject

@end

@implementation DummyObject

- (void)dealloc
{
    NSLog(@"DummyObject deallocated!");
    [super dealloc];
}

@end

@interface MyObject: NSObject
{
@private

    /** 
     * 在GNUStep庫以及Clang編譯器環境下,Block不能作為一個Objective-C物件。
     * 因此這裡只能將myBlock作為私有成員,而不能將它設定為property,
     * 然後在實現中設定其相關的getter與setter方法。
    */
    void (^myBlock)(void);

    /** 
     * 在Clang編譯器中,property尚未能自動生成與其同名的私有成員,
     * 因此必須在類的私有域中進行顯式宣告。
     * 此外,對於Clang編譯器,對成員物件的宣告只能放在類的宣告中,
     * 而不能放在實現中。
    */
    NSString *string;

    DummyObject *dummyObject;
}

@property (nonatomic, retain) NSString *string;

/** 此property用於測試使用setter方法是否能夠回收成員物件 */
@property (nonatomic, retain) DummyObject *dummyObject;

@end

@implementation MyObject

@synthesize string, dummyObject;

/** myBlock的setter方法 */
- (void)setMyBlock:(void(^)(void))block
{
    if(myBlock != NULL)
    {
        Block_release(myBlock);
        myBlock = NULL;
    }
    if(block != NULL)
        myBlock = Block_copy(block);
}

/** myBlock的getter方法 */
- (void(^)(void))myBlock
{
    return myBlock;
}

- (instancetype)init
{
    self = [super init];

    NSLog(@"MyObject initialized!");

    return self;
}

- (void)dealloc
{
    // 這裡使用屬性的setter方法進行回收成員物件
    self.myBlock = NULL;
    self.string = nil;
    self.dummyObject = nil;

    NSLog(@"MyObject deallocated!");

    [super dealloc];
}

@end

static void MyTest(void)
{
    // 測試Block語法特性
    int (^block)(int) = BlockTest();

    dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^void(void){
        puts("Hello, world!");

        int a = block(50);
        printf("a = %d\n", a);
    });

    Block_release(block);

    // 測試陣列字面量以及下標索引語法
    NSArray *array = @[@10, @20, @"Hello, world"];
    // Clang編譯器中不能直接使用陣列下標語法,諸如:NSNumber *m = array[0];
    NSNumber *m = [array objectAtIndexedSubscript:0];
    NSNumber *n = [array objectAtIndex:1];
    NSLog(@"The sum is: %d, and the string is: %@", m.intValue + n.intValue, [array objectAtIndex:2]);

    // 測試Objective-C物件以及其屬性
    DummyObject *dummyObj = [DummyObject new];

    MyObject *obj = [MyObject new];
    obj.myBlock = ^void(void){
        NSLog(@"The array size is: %tu", [array count]);
    };
    obj.string = @"This is my object!";
    obj.dummyObject = dummyObj;
    [dummyObj release];

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_sync(queue, ^void(void) {
        obj.myBlock();
        NSLog(@"obj string: %@", obj.string);
    });

    [obj release];
}

int main(void)
{
    @autoreleasepool {

        MyTest();

        NSLog(@"Program complete!");
    }
}

完了之後,我下面展示一下我自己整理好的build.sh編譯shell檔案:

clang main.m -std=gnu11 -fblocks -lBlocksRuntime -ldispatch -lgnustep-base -MMD -MP -DGNUSTEP -DGNUSTEP_BASE_LIBRARY=1 -DGNU_GUI_LIBRARY=1 -DGNU_RUNTIME=1 -DGNUSTEP_BASE_LIBRARY=1 -fno-strict-aliasing -pthread -fPIC -Wall -DGSWARN -DGSDIAGNOSE -Wno-import -O2 -fgnu-runtime -fconstant-string-class=NSConstantString -I. -I/home/zenny-chen/GNUstep/Library/Headers -I/usr/local/include/GNUstep -I/usr/include/GNUstep -I/usr/lib/gcc/x86_64-linux-gnu/5/include/    -rdynamic -fgnu-runtime -L/home/zenny-chen/GNUstep/Library/Libraries -L/usr/local/lib -L/usr/lib -lobjc -lm -o test


上述build.sh檔案中,我們使用-std=gnu11命令表示將當前的Objective-C以及C語言標準設定為符合GNU11標準語法的,即C11標準加Clang GNU擴充套件。如果我們不用GNU語法擴充套件,我們就無法使用Blocks語法。-fblocks使得Clang編譯器能解析Blocks語法,並生成相應執行時代嗎。在上述命令選項中,我把所有有關異常執行時庫的命令全都刪除了,因為我們不需要使用Objective-C的異常執行時庫。此外,我把-g命令也去掉了,因為我們也不需要對該程式進行除錯。

我們在執行build.sh的時候會發現,Clang編譯器會報一個很烏龍的錯誤——在GSVersionMacros.h中無法找到<objc/blocks_runtime.h>。我們在/usr目錄下搜尋一下objc目錄所在位置(在我的系統環境下,目錄位置為:/usr/lib/gcc/x86_64-linux-gnu/5/include/),然後我們在桌面或其他使用者目錄下建立一個blocks_runtime.h標頭檔案,輸入以下內容後用sudo拷貝到該obj目錄下。該標頭檔案內容非常簡單:

#pragma once

#ifdef __cplusplus
extern "C" {
#endif


void *_Block_copy(const void *) __attribute__((weak));
void _Block_release(const void *) __attribute__((weak));

#ifdef __cplusplus
}
#endif


然後我們再次構建的時候會發生更無語的錯誤——GSBlocks標頭檔案中對_Blocks_copy以及_Blocks_release的宣告與Block.h中的衝突。我們找到GSBlocks標頭檔案,打開發現,原來裡面宣告的_Blocks_copy與_Blocks_release的形參型別是void*,而Block.h裡宣告的則是const void*……無奈之下,我們修改一下這個原始檔,將其引數型別改為const void*就大功告成了。

我們成功編譯構建之後會發現兩個與ARC相關的警告,這些都不用理睬。

當然,如果我們不想使用跟Blocks語法相關的東東並且還想用GCC的話,也可以不折騰這些。下面我將列出不使用Blocks語法的專案配置:

gcc main.m -std=gnu11 -Os -MMD -MP -DGNUSTEP -DGNUSTEP_BASE_LIBRARY=1 -DGNU_RUNTIME=1 -DGNUSTEP_BASE_LIBRARY=1 -fno-strict-aliasing -pthread -fPIC -Wall -DGSWARN -DGSDIAGNOSE -Wno-import -fgnu-runtime -fconstant-string-class=NSConstantString  -I. -I/root/GNUstep/Library/Headers -I/usr/local/include/GNUstep -I/usr/include/GNUstep -I/usr/lib/gcc/x86_64-linux-gnu/5/include/    -rdynamic -L/root/GNUstep/Library/Libraries -L/usr/local/lib -L/usr/lib -lobjc -lm -lgnustep-base -o test

最後要說明的是,在Clang 3.8編譯器中,Objective-C能支援@autoreleasepool、複合字面量、instancetype等高階語法特性;但還不支援property自動綜合,甚至不能在類的category以及implementation中宣告成員物件。另外也不支援字典、陣列的下標索引語法,儘管GNUStep庫中已經引入了以下四個方法:

- (void)setObject:(id)object forKeyedSubscript:(id < NSCopying >)aKey;
- (id)objectForKeyedSubscript:(id)key;


- (void)setObject:(id)anObject atIndexedSubscript:(NSUInteger)index;
- (id)objectAtIndexedSubscript:(NSUInteger)index;

上面兩個用於NSMutableDictionary,下面兩個用於NSMutableArray。但是在語法層面上還不支援下標索引方式,所以在程式碼示例中用了[array objectAtIndex:0]這種形式,而不是十分簡潔的array[0]。

但總的來說,LLVM Clang 3.8還是非常不錯的,值得一用!

相關推薦

Ubuntu系統通過Clang編譯器編寫Objective-C

Objective-C作為Apple的first-class程式語言,在很長一段時間內都得到大量開發者的追捧。其中,Objective-C對C語言的完全相容、靈活性以及OOP特性,使得它成為一門十分優秀,且平衡度很高的程式語言。在我所有用過的程式語言中,Objective-C

Ubuntu系統通過命令查詢檔案或資料夾

1. whereis+檔名 用於程式名的搜尋,搜尋結果只限於二進位制檔案(引數-b)、man說明檔案(引數-m)和原始碼檔案(引數-s),如果省略引數,則返回所有資訊。 2. find / -name +檔名 find是在指定的目錄下遍歷查詢,如果目錄使用 /

Ubuntu系統OpenLDAP的安裝及配置

操作系統 ldap 前言LDAP(Lightweight Directory Access Protocol)是基於X.500標準的輕量級目錄訪問協議,在Unix操作系統裏面,和NIS,DNS一樣,屬於名稱服務(Naming Service)。本文描述了如何在Ubuntu操作系統上面,搭建LDAP服務

Ubuntu系統的Mysql安裝與使用

1=1 能夠 query val webpage mat init 字段 use 摘要 在本篇博文中。筆者將從基礎出發。介紹Mysql在Linux環境下的安裝和基本使用命令,僅適用於Mysql剛開始學習的人。大牛請繞道…… 安裝Mysql數據庫 這裏介紹最最簡單的安

-Ubuntu系統安裝srilm工具箱

路徑 需要 工具 自己 問題 ima 配置 image 可能 零、環境配置 tcl首先要下載下來c/c++ compiler GNU make,GNU gawk,GNU gzip這些最基本的也要有 環境配置不好會報錯。一開始我在自己的虛擬機上安裝的時候就各種錯誤。估計是tc

[軟件工程]在Ubuntu系統配置GIT

軟件 查看密鑰 blog hub 計算機 pan 工程 family nbsp 1.首先檢查git是否已經安裝 終端輸入git 2.如果未安裝,輸入sudo apt-get install git安裝 安裝完成之後,輸入git查看 3. 為這臺計算機起一個名字,並且登

Ubuntu系統簡單安裝python解釋器

.com linux pro -o 1.5 解釋器 col lin 下載 1、首先下載python解釋器(Linux版),我的博客裏有下載。2、下載解壓好,看下圖3、上述執行完之後,繼續在終端中執行下圖所示,4、這時候可以測試是否安裝成功了,如下圖Ubuntu系統下簡單安裝

ubuntu系統Python虛擬環境的安裝和使用

home 終端命令 兩條命令 末尾 否則 alt class pan spa 前言:進行python項目開發的時候,由於不同的項目需要使用不同的資源包和相關的配置,因此創建多個python虛擬環境,在虛擬環境下開發就顯得很有必要。 安裝虛擬環境 步驟

很簡單的在Ubuntu系統安裝字體和切換默認字體的方法

拷貝 true 桌面 技術 系統 美麗 des net 加粗 摘要: Ubuntu系統安裝好後,默認字體對於中文的支持看上去不太美麗,於是很多朋友可能需要設置系統的默認字體為自己喜歡的字體。本文主要介紹如何解決這兩個問題。 說明:測試系統是Ubuntu14.04。

在Linux系統通過TFTP或NFS燒寫內核

配置 username 配置網絡 help def 定義 不讓 服務 一行 一直想直接通過Linux系統往JZ2440開發板中燒寫內核,但網上的教程千篇一律都是借助Windows平臺上的TFTP工具燒寫的,十分不爽,因為我不喜歡在虛擬機上玩Linux!摸索了一下午,終於搞定

Ubuntu系統安裝MYSQL

成功 libmysql mys ges 51cto rep ibm ins text 操作系統版本:Ubuntu 12.0 LTS 安裝命令:sudo apt-get install mysql-server 檢查MYSQL是否安裝成功:sudo net

解決Ubuntu系統 mysql 遠程連接失敗的問題 ERROR 2003 (HY000): Can't connect to MySQL server on 'xxx.xxx.xx.xx' (110)

bind okr 解決 rul 就是 roo com 但是 serve 如果遠程連不上mysql.cnf 裏面也修改了;bind註銷掉了127.0.0.1 等所有的 但是telnet xxx.xxx.xx.xx 3306 端口 不通;那麽 就是防火墻的問題了 1.修改Ubu

迅為6818開發板Ubuntu系統CAN 測試使用文檔

.com watermark network color arm 燒寫 控制 com mod 平臺:iTOP-6818開發板系統:Ubuntu12.04主要是在 Ubuntu 系統環境下 iTOP-4418 和 6818 的 CAN 實驗調試步驟。給用戶提供了“can_li

Ubuntu系統的工控機與其他PC端的CAN通訊實現

1.問題描述: 完成Kavaser的報文收發測試後,作者想要在自己的.c檔案中呼叫CAN口傳送位置報文資訊, 在darknet/src/image.c中#include “canlib.h”,make時報錯: libdarknet.a(image.o):在函式‘draw_detect

Ubuntu系統,pip3安裝python3的pymysql包 報錯的問題

sudo pip3 list  檢視安裝的包列表 如上圖, pip升級到18.1版本. 使用pip3 出現以下錯誤: Traceback (most recent call last): File “/usr/bin/pip3”, line 9, in from pip

【Hadoop】在Ubuntu系統安裝Hadoop單機/偽分布式安裝

multi .cn 編輯器 重新 偽分布式 sources edit 信息 情況 Ubuntu 14.10 前方有坑: 由於之前的分布式系統電腦帶不動,所以想換一個偽分布式試一試。用的是Virtualbox + Ubuntu 14.10 。結果遇到了 apt-get 源無

Ubuntu系統WPS中文輸入

Ubuntu系統下WPS中文輸入 博主在Ubuntu系統下使用WPS編輯器遇到了無法輸入中文的情況,此時雖然右上角的輸入法已經切換成拼音,卻仍然無法輸入中文,只能輸入英文字母。通過下面的操作,博主解決了這個問題。 第一步 在終端輸入: sudo gedit /usr/bi

Ubuntu系統解決Qt5使用SSL的“qt.network.ssl: QSslSocket: cannot resolve SSLv2_client_method”錯誤

參考連結:https://www.cnblogs.com/btian/p/6130560.html 首先下載openssl: git clone https://github.com/openssl/openssl.git 然後選擇1.1.0穩定版,並且編譯: git check

【Eigen MKL使用】在Ubuntu系統 基於Eigen使用MKL框架和openMP框架(Qt Creator)

參考連結: 1、https://software.intel.com/en-us/articles/intel-mkl-link-line-advisor/ 2、https://blog.csdn.net/liang19890820/article/details/51774724

如何在Ubuntu系統安裝使用LaTeX

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!