objective-c - 使用 Clang 和 GNUstep 在 Debian 8 GNU/Linux 上编译 Objective-C

标签 objective-c linux debian clang gnustep

在 Debian 8 GNU/Linux 上,我正在尝试从 this tutorial 编译一些 Objective-C 代码使用 Clang 和 GNUstep make。我运行了以下命令来安装构建管道:

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

这些是我正在使用的文件:

GNUmake 文件:

CC = clang

include $(GNUSTEP_MAKEFILES)/common.make

TOOL_NAME = Main
Main_OBJC_FILES = main.m Car.m

include $(GNUSTEP_MAKEFILES)/tool.make

主要.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;
}

车.h:

#import <Foundation/Foundation.h>

@interface Car : NSObject {}

@property (copy) NSString *model;

- (void)drive;

@end

车.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;

要修复错误,我需要将 Car 界面更新为:

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

和 Car 实现:

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

似乎我当前的编译设置迫使我编写比教程建议的编译代码更多的代码。事实上,在教程中,作者特别建议不要在接口(interface)中包含“ protected 实例变量”:

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

我觉得我使用的是过时/错误配置的编译设置。我是吗?如果是这样,我该如何修复它以便我可以像引用教程中那样编写代码? (如果可能的话,我更愿意使用 GNUstep make 而不是 Clang CLI。)

最佳答案

this answer 我发现我的问题可能是我没有使用“现代”Objective-C 运行时。

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 . . .

this thread 我发现,

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

从那里,我找到了 this thread 并得出结论,我可能需要“libobjc2”。

令人失望的是,我找不到适用于 Debian 的“libobjc2”软件包,所以我尝试从源代码编译它。首先,我必须安装一些构建依赖项:

sudo apt-get install cmake llvm-dev

然后我不得不将 this patch 应用于 llvm-3.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

在那之后,我再次尝试编译教程中的代码。编译成功(没有做任何我不想做的改变)!但是,make 提示我的一个“.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

(我不能保证这是完整的依赖项列表,只有我能找到的那些;我可能已经在我的计算机上安装了一些必要的库,因此编译了不相关的程序。)

使用以下两个教程 (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 。这可能有点“清洁”并且更易于使用。我将在此处粘贴最新版本“以防万一:”

#!/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}"

关于objective-c - 使用 Clang 和 GNUstep 在 Debian 8 GNU/Linux 上编译 Objective-C,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40698870/

相关文章:

iOS8 - 不显示自定义标签栏图像

java - 操作方法 : Configure Tomcat 9 to log via Log4j2

c - 在 init_timer() 之前调用 timer_pending() 是否安全?

ios - 如何以一般形式表示 nsstring 以进行搜索或比较?

objective-c - 返回通过 "convenience constructor"初始化的对象

objective-c - 使用不活动的应用程序(后台)

linux - Centos安装chrome失败

ubuntu - 在 Ubuntu 12.04 上安装 Elasticsearch 1.0.1 失败并显示 sudo dpkg -i elasticsearch-1.0.1.deb

linux - 对字段中的 $ 值(以逗号作为千位分隔符的美国格式数字)进行排序

django - 升级到 Python 3.3 和设置 Django 的问题