09 Apr 2016
At work we use clang
and STL standard library from c++_shared
included in the NDK.
This week we have got nasty surprise when we were trying to run some code that was
throwing an exception in our async library. This seemed to happend only on ARM 32bit devices.
After a bit of digging, we have found bug report that describes more or less our situation.
We have built small test program that let us test few scenarios and that this is
really a bug in STL library shipped with Android NDK:
// jni/hello.cpp
#include <stdexcept>
#include <iostream>
int main() {
std::cerr << "1\n";
try {
throw std::runtime_error("A"); // crash! but only on arm 32bit, and when compiled with clang
} catch (std::exception& e) {}
std::cerr << "2\n";
}
## jni/Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello
LOCAL_SRC_FILES := hello.cpp
LOCAL_CPPFLAGS := -frtti -fexceptions -fPIE -pie
LOCAL_LDLIBS := -llog -pie
include $(BUILD_EXECUTABLE)
## jni/Application.mk
APP_STL:=c++_shared
APP_ABI:=armeabi-v7a
NDK_TOOLCHAIN_VERSION:=clang
To fix it, we had to switch from c++_shared
to c++_static
. However, because we had multiple shared libraries, we had to change the way we build our code, so that we don’t break ODR. Instead of building multiple shared libraries, we now build all libraries statically and link them together into one shared library.
This bug was recently fix, and should be available in the next Android NDK release (r12?).
08 Apr 2016
Let’s assume you want to create one shared library from two static libraries. Here is how to do it:
In your Android.mk
include $(CLEAR_VARS)
LOCAL_MODULE := lib1
LOCAL_SRC_FILES := lib1.cpp
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := lib2
LOCAL_SRC_FILES := lib2.cpp
include $(BUILD_STATIC_LIBRARY)
# this shared library will have all symbols from two above libraries
include $(CLEAR_VARS)
LOCAL_MODULE := lib_shared
LOCAL_SRC_FILES := empty.cpp
LOCAL_WHOLE_STATIC_LIBRARIES := lib1 lib2
include $(BUILD_SHARED_LIBRARY)
Important option to note is LOCAL_WHOLE_STATIC_LIBRARIES
. If you use regular LOCAL_STATIC_LIBRARIES
, because you don’t use any symbols from lib1
or lib2
in lib_shared
, they will be stripped at link time. To prevent this from happening LOCAL_WHOLE_STATIC_LIBRARIES
adds following options to link line to make sure symbols are not stripped:
-Wl,--whole-archive -llib1 -llib2 -Wl,--no-whole-archive
Here is documentation for --whole-archive
:
--whole-archive
For each archive mentioned on the command line after the --whole-archive
option, include every object file in the archive in the link, rather than searching the archive for the required object files. This is normally used to turn an archive file into a shared library, forcing every object to be included in the resulting shared library. This option may be used more than once.
16 Apr 2014
My team have just came back from IGK 2014 game developer conference. Below is a screenshot from our game, and link if you would like to play it: IGK2014
15 Jan 2014
While working on cross platform C++ library, I have found that this code crashes if compiled with Xcode 5:
#include <iostream>
#include <functional>
int main(int argc, const char * argv[])
{
std::function<void(int)> function = [](int){};
auto binding = std::bind(function, 10);
// crashes here with EXC_BAD_ACCESS
std::function<void()> jobFunctor = binding;
return 0;
}
When converting the result of the bind to jobFunctor
there is an infinite stack recursion in a std::function
constructor.
clang version:
$ clang++ --version
Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin12.5.0
Thread model: posix
Turns out there is official bug report about it: http://llvm.org/bugs/show_bug.cgi?id=18282
Above example works fine in Xcode 5.1.
12 Jan 2014
UITableView
can cause containing it view controller to grow significantly by implementing it’s delegates UITableViewDataSource
and UITableViewDelegate
. UITableView
controller is a solution that we come up with recently, as we were modernizing our code base to make it more modular, extensible and easier to maintain.
There are several problems when view controller implements UITableView
’s delegates directly:
- view controller grows by couple of hundred lines (depending how complex are your views)
UITableView
and it’s content is not reusable in other parts of the app
- difficult to modify, if you want to add sections or rows that are not part of your model, but rather part of presentation layer (for example, if you want to show featured articles in the additional section or last row should shows loading… when app is loading more elements for that list)
- if model is not compatible with
UITableView
(like for example hierarchy of objects that you cannot map directly to UITableViewDataSource
methods) you can end up mixing view controller’s code with logic that transforms your model to something that can be displayed as a list
- not unit testable
Instead we can implement something that I will call UITableView
controller, that moves implementation of delegates to new class, and separates different responsibilities of displaying a list. Diagram below illustrates how it works:
TableController
implements UITableViewDelegate
and UITableViewDataSource
, and delegates creating views for cells and sections to ITableViewCellFacotry
and ITableViewSectionFactory
, it also reads data from ITableViewModel
and ITableViewSectionModel
to supply UITableView
with information about number of rows and sections.
This implementation is simple and works great. In my case we had several different lists that we had to display on the screen, each list was backed by different model, but they all used the same cells to display the data. We also had cases when we have to display extra cell at the end of the section or create a whole new section that does not exist in your model, but is part of your presentation. In cases like that you can build layers of ITableViewModel
, where each layer performs one transformation, for example:
BasicTableViewModel* basicModel = [[BasicTableViewModel alloc] initWithModel:model];
// notice that order in which we perform transformations make a difference:
// 1. load more in each section + additional section for featured content without load more
// 2. additional section for featured content + load more in each section
LoadMoreTableViewModel* loadMoreModel =
[[LoadMoreTableViewModel alloc] initWithTableViewModel:basicModel ];
FeaturedTableViewModel* featuredModel =
[[FeaturedTableViewModel alloc] initWithTableViewModel:loadMoreModel];
TableController *tableController = [[TableController alloc] init];
tableController.model = featuredModel;