
brew install shark .It’s time to point out that the article deals with version 2.3.4 of the library. The project itself is already far from 2.3.4, beta version 3.0 is currently available. The code for the new version has been significantly reworked, using boost as a third-party library, so this is a completely different story, especially in the context of iOS.
VERSION=2.3.4 SHARK_ZIP=shark-$VERSION.zip # --- download() { if [ ! -s $SHARK_ZIP ]; then echo Downloading shark source code $SHARK_ZIP... curl -L --progress-bar -o $SHARK_ZIP "http://sourceforge.net/projects/shark-project/files/Shark%20Core/Shark%20${VERSION}/shark-${VERSION}.zip/download" else echo Source code $SHARK_ZIP already downloaded... fi doneSection } SRC_DIR=src # --- unpackSource() { echo Unpacking $SHARK_ZIP to $SRC_DIR... [ -d $SRC_DIR ] || unzip -q $SHARK_ZIP -d $SRC_DIR [ -d $SRC_DIR ] && echo " ...unpacked as $SRC_DIR" doneSection } ReClaM/EarlyStopping.cpp . EarlyStopping::EarlyStopping(unsigned sl = 5) EarlyStopping has a single argument ( unsigned sl ) and the default value ( 5 ) is specified for this argument. Thus, this constructor becomes the default constructor, “so be it,” gcc 4.2 says, but clang has a completely different opinion on this. On StackOverflow, you can find a discussion of this error. EarlyStopping::EarlyStopping(unsigned sl) sl .finite(x) function is not available (not included) for iOS, either for devices or for a simulator. On the network, you can find references to this problem, for example here .isfinite(x) function. Override finite(x) as isfinite(x) using preprocessing macros, to do this, add the following code to SharkDefs.h #if defined(__APPLE__) && defined(__MACH__) /* Apple OSX and iOS (Darwin). */ #include <TargetConditionals.h> #if TARGET_IPHONE_SIMULATOR == 1 /* iOS in Xcode simulator */ #define finite(x) isfinite(x) #elif TARGET_OS_IPHONE == 1 /* iOS on iPhone, iPad, etc. */ #define finite(x) isfinite(x) // #define drem(x, y) remainder(x, y) #elif TARGET_OS_MAC == 1 /* OSX */ #endif #endif __APPLE__ and __MACH__ , then we include the header file TargetConditionals.h , then we check the values TARGET_IPHONE_SIMULATOR , TARGET_OS_IPHONE and TARGET_OS_MAC , and redefine the finite(x) for the iOS device and simulator.drem(x, y) function, which needs to be replaced with remainder(x, y) . However, Shark drem(x, y) does not use, so this is just a note of information.FileUtil module, namely the FileUtil.h file.iotype type iotype and SetDefault , ScanFrom and PrintTo . Let's give the compiler a hint using the namespace, i.e. perform a simple replacement where needed iotype -> FileUtil::iotype SetDefault -> FileUtil::SetDefault ScanFrom -> FileUtil::ScanFrom PrintTo -> FileUtil::PrintTo io_strict function, which calls the scanFrom_strict and printTo_strict functions declared later.io_strict to the end of the file and there is no problem.Mixture/MixtureOfGaussians.cpp mark the following code as invalid extern "C" double erf(double) throw(); extern "C" declaration does not match the original prototype.throw() . extern "C" double erf(double); I am aware that for some corrections I do not give a detailed explanation, such as removing throw() . I would be happy to comment in the comments.Mixture/RandomVector.h , line 72. The compiler has no idea how to Mixture/RandomVector.h with p . Also alarming is the comment to the code in this line ( // !!! ). for (unsigned k = x.dim(0); k--;) { l += log(Shark::max(p(x[ k ]), 1e-100)); // !!! } p . RandomVector inherits RandomVar , which declared the "lost" method p . // RandomVar.h template < class T > class RandomVar { public: // *** virtual double p(const T&) const = 0; // *** } // RandomVector.h template < class T > class RandomVector : public RandomVar< Array< T > > { public: // *** } this->p . for (unsigned k = x.dim(0); k--;) { l += log(Shark::max(this->p(x[ k ]), 1e-100)); // !!! } CMakeLists.txt file. ADD_LIBRARY( shark SHARED ${SRCS} ) # ADD_LIBRARY( shark STATIC ${SRCS} ) diff utility. diff -crB shark_orig shark_patched > shark.patch patch SRC_DIR=src # --- patchSource() { echo Patching source code... patch -d $SRC_DIR/Shark -p1 --forward -r - -i ../../shark.patch doneSection } make , it remains only to configure everything correctly for each platform, this will be helped by the utility cmake (configure make), which will create a Makefile and other files needed by make . We will have to configure and build the library 3 times, for the following platforms and architecturesarmv7 , armv7s , arm64 architecturesi386 and x86_64x86_64Yes, an important point, we will use Xcode 5. Support for the architecture of armv6 officially removed from Xcode 5, so we don’t consider it at all.cmake . For each platform, we need to properly configure the environment using the following settingsCMAKE_CXX_COMPILER )/usr/bin/c++ , we also need to use clang++ from the Xcode toolchain.CMAKE_CXX_FLAGS )CMAKE_C_COMPILER )CMAKE_OSX_SYSROOT )CMAKE_INSTALL_PREFIX )make install command, but we will not do this.-G flag)cmake generate the familiar Makefile . It would be logical to use the Xcode project, but I was not able to collect everything in this way.xcode-select --install .xcode-select to find all the necessary tools and directories. # XCODE_ROOT=$(xcode-select -print-path) # iPhone OS SDK XCODE_ARM_ROOT=$XCODE_ROOT/Platforms/iPhoneOS.platform/Developer # iPhone Simulator SDK XCODE_SIM_ROOT=$XCODE_ROOT/Platforms/iPhoneSimulator.platform/Developer # , ... XCODE_TOOLCHAIN_BIN=$XCODE_ROOT/Toolchains/XcodeDefault.xctoolchain/usr/bin # C++ CXX_COMPILER=${XCODE_TOOLCHAIN_BIN}/clang++ # C C_COMPILER=${XCODE_TOOLCHAIN_BIN}/clang cmake is smart enough to find the root system directory on its own, without further instructions.build/ios .armv7 , armv7s and arm64 architectures, we will use the special -arch flag for clang++ .SDKs/iPhoneOS7.0.sdk subdirectory of XCODE_ARM_ROOT CXX_FLAGS="-arch armv7 -arch armv7s -arch arm64" SYSTEM_ROOT=${XCODE_ARM_ROOT}/SDKs/iPhoneOS7.0.sdk cmake call will look like this. mkdir -p build/ios cd build/ios cmake \ -DCMAKE_CXX_COMPILER=$CXX_COMPILER \ -DCMAKE_OSX_SYSROOT="$SYSTEM_ROOT" \ -DCMAKE_C_COMPILER=$C_COMPILER \ -DCMAKE_CXX_FLAGS="$CXX_FLAGS" \ -G "Unix Makefiles" \ ../../src/Shark By the way,cmakewill do a lot of extra work for us. We only need to specify C and C ++ compilers,cmakewill find all other utilities from the same toolkit, for example,ranlib,lipo,ld, etc.
i386 and x86_64 , the latter is needed for testing on a simulator of devices with 64-bit architecture, for example, “iPhone Retina (4-inch 64-bit)”.${XCODE_SIM_ROOT}/SDKs/iPhoneSimulator7.0.sdk .-mios-simulator-version-min=7.0 flag mkdir -p build/sim cd build/sim CXX_FLAGS="-arch i386 -arch x86_64 -mios-simulator-version-min=7.0" SYSTEM_ROOT=${XCODE_SIM_ROOT}/SDKs/iPhoneSimulator7.0.sdk cmake \ -DCMAKE_CXX_COMPILER=$CXX_COMPILER \ -DCMAKE_OSX_SYSROOT="$SYSTEM_ROOT" \ -DCMAKE_C_COMPILER=$C_COMPILER \ -DCMAKE_CXX_FLAGS="$CXX_FLAGS" \ -G "Unix Makefiles" \ ../../src/Shark cmake will find everything else itself. mkdir -p build/osx cd build/osx cmake \ -DCMAKE_CXX_COMPILER=$CXX_COMPILER \ -DCMAKE_C_COMPILER=$C_COMPILER \ -G "Unix Makefiles" \ ../../src/Shark cmakemake !, - you think, but no.cmake has a couple of features to consider.cmake runs a test for C and C ++ compilers. Oddly enough, clang and clang ++ successfully fail this test for iOS platforms. On the Internet, there are several recommendations on how to bypass this test, for example, in the CMakeLists.txt file, add NONE to the project description, but this did not help me. PROJECT( shark NONE ) cmake without specifying clang and clang ++ compilers and other options. cmake generate a CMakeCache.txt file and a CMakeFiles directory. If you now run cmake with different settings, the compilers test will not be executed this time.cmake at least 2 times - you will think again.cmake will issue a warning and advise you to run it again. In fact, cmake will not say anything like that, but the ccmake utility ccmake provide more information. ccmake is a console graphic interface for cmake .cmake , without parameters to pass the testcmake , with the necessary parameterscmake to make changes take effect.make . To make things go faster, you can parallelize the assembly using the -j flag. make -j16 libshark.a in our hands. For every fireman, with the help of the file utility, make sure that the resulting libraries support all the necessary architectures. $ file build/ios/libshark.a build/ios/libshark.a: Mach-O universal binary with 3 architectures build/ios/libshark.a (for architecture armv7): current ar archive random library build/ios/libshark.a (for architecture armv7s): current ar archive random library build/ios/libshark.a (for architecture cputype (16777228) cpusubtype (0)): current ar archive random library $ file build/sim/libshark.a build/sim/libshark.a: Mach-O universal binary with 2 architectures build/sim/libshark.a (for architecture i386): current ar archive random library build/sim/libshark.a (for architecture x86_64): current ar archive random library $ file build/osx/libshark.a build/osx/libshark.a: current ar archive random library lipo utility will cope with this task lipo mkdir -p lib/ios $XCODE_TOOLCHAIN_BIN/lipo -create build/ios/libshark.a build/sim/libshark.a -o lib/ios/libshark.a file lib/ios/libshark.a ) to make sure that all 5 architectures are in place.Shark.framework directory and the necessary folder structure inside, with all the necessary symbolic links, using mkdir and ln for this. Shark.framework/ ├── Documentation -> Versions/Current/Documentation ├── Headers -> Versions/Current/Headers ├── Resources -> Versions/Current/Resources └── Versions ├── A │ ├── Documentation │ ├── Headers │ └── Resources └── Current -> A Shark . cp build/ios/libshark.a Shark.framework/Versions/A/Shark .h files from the src/Shark/include to the Headers folder inside the bundle. Then remove the unnecessary statistics.h . This file is not needed at least because there is no corresponding INSTALL command in the CMakeLists.txt file. cp -r src/Shark/include/* Shark.framework/Headers/ rm Shark.framework/Headers/statistics.h #include directives, we will have to do this work for them.#include directives for boost components start with boost/ , for example #include "boost/config.hpp" #include <boost/type_traits/remove_reference.hpp> sed editor and patch files using the following rules for all #include directivesSharkDefs.h with Shark/SharkDefs.hShark/ in the path for all components of the libraryHeaders folder, i.e. Array, Rng, LinAlg, FileUtil, EALib, MOO-EALib, ReClaM, Mixture, TimeSeries, Fuzzy . # "invalid character sequence" export LC_TYPE=C export LANG=C # #include # SharkDefs.h # # -E , "gnu vs non-gnu sed" components="Array|Rng|LinAlg|FileUtil|EALib|MOO-EALib|ReClaM|Mixture|TimeSeries|Fuzzy" find Shark.framework/Headers -type f -exec \ sed -E -i '' \ -e "s,#include([<\"]),#include \1,g" \ -e "s,#include([ \t])([<\"])(SharkDefs.h),#include\1\2Shark/\3,g" \ -e "s,#include([ \t])([<\"])(${components}/),#include\1\2Shark/\3,g" \ {} + FRAMEWORK_NAME=Shark FRAMEWORK_CURRENT_VERSION=2.3.4 cat > Shark.framework/Resources/Info.plist <<EOF <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleDevelopmentRegion</key> <string>English</string> <key>CFBundleExecutable</key> <string>${FRAMEWORK_NAME}</string> <key>CFBundleIdentifier</key> <string>dk.diku.image</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundlePackageType</key> <string>FMWK</string> <key>CFBundleSignature</key> <string>????</string> <key>CFBundleVersion</key> <string>${FRAMEWORK_CURRENT_VERSION}</string> </dict> </plist> EOF Before the release of iOS 7, namely, devices with thearm64architecture, it was possible to create universal static libraries, and therefore frameworks, simultaneously for iOS and OSX, including a simulator. Nothing prevented packingarmv6, armv7, armv7s, i386andx86_64into one bold library. Devices with 64-bit architecture confused all the cards. In a “thick” library, there cannot be two layers with the same architecture, which means you cannot getx86_64for iOS simulator of 64-bit devices andx86_64for OS X.
Pod::Spec.new do |s| s.name = 'Shark-SDK' s.version = '2.3.4' s.license = { :type => 'GPLv2', :text => 'See https://sourceforge.net/directory/license:gpl/' } s.summary = 'iOS & OS X framework for Shark: C++ Machine Learning Library' s.description = <<-DESC SHARK provides libraries for the design of adaptive systems, including methods for linear and nonlinear optimization (eg, evolutionary and gradient-based algorithms), kernel-based algorithms and neural networks, and other machine learning techniques. DESC s.homepage = 'https://sourceforge.net/projects/shark-project/' s.author = { 'shark-admin' => 'https://sourceforge.net/u/shark-admin/profile/' } s.source = { :http => 'https://github.com/mgrebenets/shark2-iosx/releases/download/v2.3.4/Shark-SDK.tgz', :type => :tgz } s.ios.vendored_frameworks = "Shark-iOS-SDK/Shark.framework" s.osx.vendored_frameworks = "Shark-OSX-SDK/Shark.framework" s.ios.deployment_target = '6.0' s.osx.deployment_target = '10.7' end # Podfile platform :ios, :deployment_target => '6.0' pod 'Shark-SDK' target :'shark2-osx-demo', :exclusive => true do platform :osx, :deployment_target => '10.7' pod 'Shark-SDK' end Source: https://habr.com/ru/post/208052/
All Articles