来自this answer,我发现我的问题可能是我没有使用“现代”Objective-C 运行时。
@implementation { } 块内的实例变量声明是
一个相对较新的 Objective-C 特性。 . . .你还需要
符合“现代”Objective-C 运行时的条件。 . .
从this thread我找到了,
提供 -fobjc-nonfragile-abi 也会对
运行。在 Darwin 上,它将使用 Apple 的“现代”运行时,而不是
指定它将为“旧版”运行时生成代码。如果你
指定 -fobjc-nonfragile-abi 和 -fgnu-runtime,然后 clang 将
为 GNUstep 运行时生成代码,您可以在 GNUstep 中找到它
svn 作为 libobjc2。这提供了 ObjC 2 的所有功能,除了
GC,以及其他一些在 Mac 运行时中找不到的内容。
所以,我尝试将以下内容添加到我的 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}"