2016-11-19 11 views
1

Debian 8 GNU/Linuxでは、ClangとGNUstep makeを使ってObjective-Cコードをthis tutorialからコンパイルしようとしています。私は、ビルドパイプラインをインストールするには、以下のコマンドを実行しました:Debian 8でObjective-CをコンパイルするClangとGNUstepを使ってGNU/Linuxを作る

たGNUmakefile:

sudo apt-get install build-essential clang gnustep-devel 

をこれらは私が使用しているファイルです

CC = clang 

include $(GNUSTEP_MAKEFILES)/common.make 

TOOL_NAME = Main 
Main_OBJC_FILES = main.m Car.m 

include $(GNUSTEP_MAKEFILES)/tool.make 

main.m:

#import <Foundation/Foundation.h> 
#import "Car.h" 

int main() { 
    @autoreleasepool { 
    Car *toyota = [[Car alloc] init]; 

    [toyota setModel:@"Toyota Corolla"]; 
    NSLog(@"Created a %@", [toyota model]); 

    toyota.model = @"Toyota Camry"; 
    NSLog(@"Changed the car to a %@", toyota.model); 

    [toyota drive]; 
    } 
    return 0; 
} 

Car.h:

#import <Foundation/Foundation.h> 

@interface Car : NSObject {} 

@property (copy) NSString *model; 

- (void)drive; 

@end 

Car.m:

#import "Car.h" 

@implementation Car { 
    double _odometer; 
} 

@synthesize model = _model; 

- (void)drive { 
    NSLog(@"Driving a %@. Vrooom!", self.model); 
} 

@end 

私はでコンパイルしています:

. /usr/share/GNUstep/Makefiles/GNUstep.sh && make -k 

私はコンパイルするとき、私は次のエラーを取得:エラーを修正するには

Car.m:4:10: error: inconsistent number of instance variables specified 
    double _odometer; 
     ^
Car.m:7:13: error: synthesized property 'model' must either be named the same as a compatible instance variable or must 
     explicitly name an instance variable 
@synthesize model = _model; 

を、私はカーインターフェイスを次のように更新する必要があります。

@interface Car : NSObject { 
    NSString * _model; 
    double _odometer; 
} 

や車の実装:

@implementation Car { 
    NSString * _model; 
    double _odometer; 
} 

チュートリアルをコンパイルするために必要とされている示唆しているよりも、私の現在のコンパイルの設定がより多くのコードを書くために私を余儀なくされたように思えます。実際には、チュートリアルでは、著者は、具体的インターフェースで「保護されたインスタンス変数」を含めないことをお勧めします:

@interface Car : NSObject { 
    // Protected instance variables (not recommended) 
} 

私は時代遅れ/誤設定、コンパイルの設定を使用していますように私は感じます。私ですか?もしそうなら、私はそれを修正して、参考チュートリアルのようなコードを書くことができますか? (可能であれば、Clang CLIではなくGNUstep makeを使用することをお勧めします)

答えて

1

@synthesize model = _model;を使用するには、チュートリアルに間違いがあります実際には_modelという名前のインスタンス変数を定義する必要があります。あなたがそうすると、エラーは消えます。

もう一度やり直しましょう。長い間、Objective-Cはプロパティを定義するための構文が@propertyではありませんでした。このチュートリアルでは@property (copy) NSString *model;と表示されていますが、すぐにその意味を理解することはできません。 (リンク「properties module」はこのテーマについて著者からの多くを見るために読んでください。)@property構文の前に、あなたは手動であなたのインスタンス変数のすべてを定義し

// In MyClass.h 
@interface MyClass : NSObject { 
    // Visible instance variables. Can be marked @public, @private, and @protected to prevent access. 
} 
... 
@end 

にユーザーがアクセスすることを可能にするために、あなたのセッターとゲッター(例:-model-setModel:)を記述し、インスタンス変数をアクセスできない状態にすることは良い習慣でした。これは、内部状態へのアクセスを保護し、プレゼン可能なインタフェースを介してのみアクセスを許可するOOPモデルに従います。

これはかなり面倒なプロセスであり、多くの定型文(特に手動メモリ管理、KVO準拠など)でした。 @propertyという構文が役立ちました。

@propertyを宣言すると、インスタンス変数が定義され、暗黙的にgetterおよびsetterメソッドが作成されます。これらのgetterおよびsetterで使用するメモリ管理モデル(たとえば、strongweakassigncopyなど)、アトミック性などを指定できます。 modelというプロパティがある場合、-model-setModel:(ゲッターだけを定義しない限り)-modelと一緒にインスタンス変数が生成され、@propertyが生成されます。

ただし、@propertyではありませんでした。は、ゲッターとセッターだけをインスタンス変数として作成します。インスタンス変数が必要な場合は、自分で作成するか、コンパイラーに明示的に要求する必要があります。 @synthesize行が入っています。@synthesize model = _model;は、自分で_modelインスタンス変数を作成したことをコンパイラに伝え、modelプロパティは_modelをストレージとして使用する必要があります。プロパティの先頭のアンダースコアは、プロパティ自体(セッター/ゲッターのエイリアス)とその下にあるストレージを区別するのに役立つ単純な規則です。

いずれにしても、これは過去の詳細です。最新のコンパイラでは、@synthesize行は必要ありません。コンパイラがインスタンス変数を生成するためです。変数を自分で追加し、@synthesize model = _model;行(推奨しません)のままにするか、その行をそのままにしてください。

も注意してください、あなた自身のインスタンス変数を宣言した場合、彼らはない必要性を行うことを、あなたの@interface@implementationの間で繰り返される - 場所を選んで、そこにそれらを置きます。 @implementationは表示する必要はないのでお勧めしますが、それはあなた次第です。

+0

Reおよびコードブロック「@property構文の前に」、私の記憶がこれに完璧ではないですが、実装セクションでアイバーズの宣言を追加しましたそれは宣言されたプロパティと同じくらいの時間であり、私はそれが非脆弱な象牙の変化に対応/依存していると信じています。 –

+0

@JoshCaswell私はあなたが正しいと思います。 –

2

投稿者this answer私の問題は、「現代的な」Objective-Cランタイムを使用していない可能性があることがわかりました。私が見つけたthis threadから

Instance variable declarations inside the @implementation { } block is a relatively recent Objective-C feature. . . . you also need to be eligible for the "Modern" Objective-C runtime . . .

、そう

Providing -fobjc-nonfragile-abi will also make some changes to the runtime. On Darwin it will use Apple's 'Modern' runtime, while not specifying it will generate code for the 'Legacy' runtime. If you specify -fobjc-nonfragile-abi and -fgnu-runtime, then clang will generate code for the GNUstep runtime, which you can find in GNUstep svn as libobjc2. This provides all of the ObjC 2 features except for GC, and a few others not found in the Mac runtimes.

、私は私たGNUmakefileに以下を追加してみました:

Main_OBJCFLAGS = -fobjc-nonfragile-abi 

しかし、私がコンパイルしようとしたとき、私はエラーを得た:

fatal error: 'objc/blocks_runtime.h' file not found 

Frそこでは、私はthis threadを見つけ、おそらく "libobjc2"が必要だと結論づけました。

私はDebian用の "libobjc2"パッケージを見つけられませんでしたので、ソースからコンパイルしようとしました。まず、私はいくつかのビルド依存関係をインストールする必要がありました:

sudo apt-get install cmake llvm-dev 

は、それから私は、LLVM-3にthis patchを適用しなければなりませんでした。5-devパッケージ、それはlibobjc2のコンパイルが失敗する原因となったために:

wget -qO- https://launchpadlibrarian.net/221945609/fix-llvm-3.5-dev-debian.bash | bash 

それでは、私は次のコマンドを使用してlibobjc2をコンパイルすることができた。その後

wget http://download.gna.org/gnustep/libobjc2-1.7.tar.bz2 
tar jxf libobjc2-1.7.tar.bz2 
cd libobjc2-1.7 
mkdir Build 
cd Build 
CC=clang CXX=clang++ cmake -DCMAKE_INSTALL_LIBDIR=lib .. 
make -j8 
sudo -E make install 

、私はコンパイルしてみましたもう一度チュートリアルのコードを入力してください。編集は成功しました(私がしたくない変更を加えずに)!しかし、私の ".so"ファイル(正確なエラーを思い出すことはできません)の間の "潜在的な矛盾"について苦情を申し立てました。プログラムを実行したとき(./obj/Main)、プログラムの出力で次のようになりました。

$ ./obj/Main 
Loading two versions of Protocol. The class that will be used is undefined 
Loading two versions of Object. The class that will be used is undefined 
2016-11-19 16:43:24.012 Main[10166] Created a Toyota Corolla 
2016-11-19 16:43:24.017 Main[10166] Changed the car to a Toyota Camry 
2016-11-19 16:43:24.017 Main[10166] Driving a Toyota Camry. Vrooom! 

どうやら、libobjc2をコンパイルし、DebianのGNUstepのパッケージと一緒に生き、それをさせることは「良い」ではなかったかもしれませんだから、私は様々なオンラインソースのアドバイスを受けて、ソースからGNUstepをコンパイルする準備をしました。

まず私は、Debianパッケージをアンインストール:

sudo apt-get uninstall gnustep-devel && sudo apt-get autoremove 

は、それから私は、依存関係を構築し、次のインストール:

sudo apt-get install libffi-dev libicu-dev libgnutls28-dev libxml2-dev libxslt1-dev libtiff5-dev libjpeg-dev libpng-dev libgif-dev libaspell-dev libcups2-dev libaudiofile-dev portaudio19-dev libdispatch-dev 

(私はそれが依存関係の完全なリストです保証することはできません、唯一のものIドキュメントが見つかりました;無関係なプログラムをコンパイルした結果、コンピュータにインストールされているライブラリがもう少し必要になることがあります)

foll 2つのチュートリアル(1)(2)のために、それらをわずかに(おそらく不必要に)調整して、私はGNUstepをコンパイルすることができました。その後

wget -qO- ftp://ftp.gnustep.org/pub/gnustep/core/gnustep-make-2.6.8.tar.gz | tar xz 
wget -qO- ftp://ftp.gnustep.org/pub/gnustep/core/gnustep-base-1.24.9.tar.gz | tar xz 
wget -qO- ftp://ftp.gnustep.org/pub/gnustep/core/gnustep-gui-0.25.0.tar.gz | tar xz 
wget -qO- ftp://ftp.gnustep.org/pub/gnustep/core/gnustep-back-0.25.0.tar.gz | tar xz 

cd gnustep-make-2.6.8 
CC=clang ./configure --enable-objc-nonfragile-abi 
sudo make install 
cd .. 

cd gnustep-base-1.24.9 
CC=clang OBJCFLAGS="-fblocks -fobjc-nonfragile-abi" ./configure 
CC=clang OBJCFLAGS="-fblocks -fobjc-nonfragile-abi" make 
sudo make install 
cd .. 

cd gnustep-gui-0.25.0 
CC=clang OBJCFLAGS="-fblocks -fobjc-nonfragile-abi" ./configure 
CC=clang OBJCFLAGS="-fblocks -fobjc-nonfragile-abi" make 
sudo make install 
cd .. 

cd gnustep-back-0.25.0 
CC=clang OBJCFLAGS="-fblocks -fobjc-nonfragile-abi" ./configure 
CC=clang OBJCFLAGS="-fblocks -fobjc-nonfragile-abi" make 
sudo make install 
cd .. 

、私は、再びこの時間を私のチュートリアルファイルをコンパイル:最後に

. /usr/local/share/GNUstep/Makefiles/GNUstep.sh && make -k 

、私はもはや「紛争」に関するエラーを取得していない、と私は、プログラムを実行すると、私はもはや、 "二つのバージョンをロードしています..."という形式のエラーを見ていません。

$ ./obj/Main 
2016-11-19 19:56:07.450 Main[10822:10822] Created a Toyota Corolla 
2016-11-19 19:56:07.451 Main[10822:10822] Changed the car to a Toyota Camry 
2016-11-19 19:56:07.451 Main[10822:10822] Driving a Toyota Camry. Vrooom! 

成功!

私はこのソリューションをわずかにa scriptにリファクタリングしました。それは少し「よりクリーンで使いやすい」かもしれません。 I「念のために:」ここに最新版を貼り付けます

#!/usr/bin/env bash 

# It seems that many modern Objective-C features aren't available without 
# libobjc2, which doesn't seem to be available as a Debian package. Also, 
# compiling and using it alongside the Debian GNUstep packages doesn't work too 
# well (it seems like they may each provide their own definition of the Protocol 
# and Object classes). Basically, to get a fully-functioning Objective-C 
# compilation environment on Debian 8, run this script. 

# Please ensure any Debian GNUstep packages are uninstalled before running this 
# script. 

# Slightly adapted from 
# http://wiki.gnustep.org/index.php/GNUstep_under_Ubuntu_Linux for Debian 8. 
# Also, uses the latest stable versions of source packages as of this writing 
# (hopefully to improve reproducability of success; but feel free to upgrade 
# them if you want). 

# If this script is successful, you should be able to compile a "main.m" program 
# by running "make" in a directory with a "GNUmakefile" with these contents: 
# 
#  include $(GNUSTEP_MAKEFILES)/common.make 
#  TOOL_NAME = Main 
#  Main_OBJC_FILES = main.m 
#  include $(GNUSTEP_MAKEFILES)/tool.make 

# Show prompt function 
function showPrompt() 
{ 
    if [ "$PROMPT" = true ] ; then 
     echo -e "\n\n" 
     read -p "${GREEN}Press enter to continue...${NC}" 
    fi 
} 

# Set colors 
GREEN=`tput setaf 2` 
NC=`tput sgr0` # No Color 

# Set to true to pause after each build to verify successful build and installation 
PROMPT=true 

# Install Requirements 
sudo apt update 

echo -e "\n\n${GREEN}Installing dependencies...${NC}" 
sudo apt -y install clang ninja cmake libffi-dev libxml2-dev \ 
    libgnutls28-dev libicu-dev libblocksruntime-dev libkqueue-dev libpthread-workqueue-dev autoconf libtool \ 
    libjpeg-dev libtiff5-dev libffi-dev libcairo2-dev libx11-dev libxt-dev libxft-dev \ 
    llvm-dev libdispatch-dev 

# https://bugs.launchpad.net/ubuntu/+source/llvm/+bug/1387011/comments/17 
wget -qO- https://launchpadlibrarian.net/221945609/fix-llvm-3.5-dev-debian.bash | bash 

# Create build directory 
mkdir GNUstep-build 
cd GNUstep-build 

# Set clang as compiler 
export CC=clang 
export CXX=clang++ 

# Checkout sources 
echo -e "\n\n${GREEN}Downloading sources...${NC}" 
mkdir -p libobjc2 && wget -qO- https://github.com/gnustep/libobjc2/archive/v1.8.1.tar.gz | tar xz -C libobjc2 --strip-components=1 
mkdir -p make && wget -qO- ftp://ftp.gnustep.org/pub/gnustep/core/gnustep-make-2.6.8.tar.gz | tar xz -C make --strip-components=1 
mkdir -p base && wget -qO- ftp://ftp.gnustep.org/pub/gnustep/core/gnustep-base-1.24.9.tar.gz | tar xz -C base --strip-components=1 
mkdir -p gui && wget -qO- ftp://ftp.gnustep.org/pub/gnustep/core/gnustep-gui-0.25.0.tar.gz | tar xz -C gui --strip-components=1 
mkdir -p back && wget -qO- ftp://ftp.gnustep.org/pub/gnustep/core/gnustep-back-0.25.0.tar.gz | tar xz -C back --strip-components=1 

showPrompt 

# Build GNUstep make first time 
echo -e "\n\n" 
echo -e "${GREEN}Building GNUstep-make for the first time...${NC}" 
cd make 
./configure --enable-debug-by-default --with-layout=gnustep --enable-objc-nonfragile-abi --enable-objc-arc 
make -j8 
sudo -E make install 

. /usr/GNUstep/System/Library/Makefiles/GNUstep.sh 
echo ". /usr/GNUstep/System/Library/Makefiles/GNUstep.sh" >> ~/.bashrc 

# showPrompt 

# Build libobjc2 
echo -e "\n\n" 
echo -e "${GREEN}Building libobjc2...${NC}" 
cd ../libobjc2 
rm -Rf build 
mkdir build && cd build 
cmake ../ -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang -DCMAKE_ASM_COMPILER=clang -DTESTS=OFF 
cmake --build . 
sudo -E make install 
sudo ldconfig 

export LDFLAGS=-ldispatch 

showPrompt 

OBJCFLAGS="-fblocks -fobjc-runtime=gnustep-1.8.1" 

# Build GNUstep make second time 
echo -e "\n\n" 
echo -e "${GREEN}Building GNUstep-make for the second time...${NC}" 
cd ../../make 
./configure --enable-debug-by-default --with-layout=gnustep --enable-objc-nonfragile-abi --enable-objc-arc 
make -j8 
sudo -E make install 

. /usr/GNUstep/System/Library/Makefiles/GNUstep.sh 

showPrompt 

# Build GNUstep base 
echo -e "\n\n" 
echo -e "${GREEN}Building GNUstep-base...${NC}" 
cd ../base/ 
./configure 
make -j8 
sudo -E make install 

showPrompt 

# Build GNUstep GUI 
echo -e "\n\n" 
echo -e "${GREEN} Building GNUstep-gui...${NC}" 
cd ../gui 
./configure 
make -j8 
sudo -E make install 

showPrompt 

# Build GNUstep back 
echo -e "\n\n" 
echo -e "${GREEN}Building GNUstep-back...${NC}" 
cd ../back 
./configure 
make -j8 
sudo -E make install 

showPrompt 

. /usr/GNUstep/System/Library/Makefiles/GNUstep.sh 

echo -e "\n\n" 
echo -e "${GREEN}Install is done. Open a new terminal to start using.${NC}" 
+0

ほとんどの場合、問題を解決してくれたことをよく知っています - 現代のランタイムは良いことです。しかし、最初の場所に独自のインスタンス変数を追加する理由はありません。特定のABI要件や、独自のインスタンス変数を指定する明示的な理由がない限り(プロパティを使用したくない、本当にプライベートストレージが必要ななど)、プロパティで十分です。これらの問題はほとんど直交しています。 –

関連する問題