提交 ca137372 编写于 作者: L liuruilong

add metal loader and skeleton code

上级 80a4dbdb
......@@ -69,3 +69,24 @@ build
# clion building directories
cmake-build-debug
cmake-build-release
# Pods
Podfile.lock
SwiftProtobuf.framework
metal/paddle-mobile/Pods/
example/paddle-mobile-demo/paddle-mobile-demo/yolo/
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
FC111A6620DD31C700F213F8 /* test.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC111A6520DD31C700F213F8 /* test.pb.swift */; };
FC111BE320DE079E00F213F8 /* params in Resources */ = {isa = PBXBuildFile; fileRef = FC111BE120DE079E00F213F8 /* params */; };
FC111BE420DE079E00F213F8 /* model in Resources */ = {isa = PBXBuildFile; fileRef = FC111BE220DE079E00F213F8 /* model */; };
FC9F52F120DA7F4D00C9F612 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC9F52F020DA7F4D00C9F612 /* AppDelegate.swift */; };
FC9F52F320DA7F4D00C9F612 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC9F52F220DA7F4D00C9F612 /* ViewController.swift */; };
FC9F52F620DA7F4D00C9F612 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FC9F52F420DA7F4D00C9F612 /* Main.storyboard */; };
FC9F52F820DA7F4F00C9F612 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FC9F52F720DA7F4F00C9F612 /* Assets.xcassets */; };
FC9F52FB20DA7F4F00C9F612 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FC9F52F920DA7F4F00C9F612 /* LaunchScreen.storyboard */; };
FCBF210620DC007900B5FDF0 /* paddle_mobile.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FCBF210520DC007900B5FDF0 /* paddle_mobile.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
FCBF210720DC007900B5FDF0 /* paddle_mobile.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = FCBF210520DC007900B5FDF0 /* paddle_mobile.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
FCBF210820DC00A100B5FDF0 /* SwiftProtobuf.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FCBF20FC20DBFF4D00B5FDF0 /* SwiftProtobuf.framework */; };
FCBF210920DC00A100B5FDF0 /* SwiftProtobuf.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = FCBF20FC20DBFF4D00B5FDF0 /* SwiftProtobuf.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
FCBF210420DC005100B5FDF0 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
FCBF210720DC007900B5FDF0 /* paddle_mobile.framework in Embed Frameworks */,
FCBF210920DC00A100B5FDF0 /* SwiftProtobuf.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
FC111A6520DD31C700F213F8 /* test.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = test.pb.swift; sourceTree = "<group>"; };
FC111BE120DE079E00F213F8 /* params */ = {isa = PBXFileReference; lastKnownFileType = file; path = params; sourceTree = "<group>"; };
FC111BE220DE079E00F213F8 /* model */ = {isa = PBXFileReference; lastKnownFileType = file; path = model; sourceTree = "<group>"; };
FC9F52ED20DA7F4D00C9F612 /* paddle-mobile-demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "paddle-mobile-demo.app"; sourceTree = BUILT_PRODUCTS_DIR; };
FC9F52F020DA7F4D00C9F612 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
FC9F52F220DA7F4D00C9F612 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
FC9F52F520DA7F4D00C9F612 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
FC9F52F720DA7F4F00C9F612 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
FC9F52FA20DA7F4F00C9F612 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
FC9F52FC20DA7F4F00C9F612 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
FCBF20FC20DBFF4D00B5FDF0 /* SwiftProtobuf.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = SwiftProtobuf.framework; sourceTree = "<group>"; };
FCBF210520DC007900B5FDF0 /* paddle_mobile.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = paddle_mobile.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
FC9F52EA20DA7F4D00C9F612 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
FCBF210620DC007900B5FDF0 /* paddle_mobile.framework in Frameworks */,
FCBF210820DC00A100B5FDF0 /* SwiftProtobuf.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
FC111BE020DE079E00F213F8 /* yolo */ = {
isa = PBXGroup;
children = (
FC111BE120DE079E00F213F8 /* params */,
FC111BE220DE079E00F213F8 /* model */,
);
path = yolo;
sourceTree = "<group>";
};
FC9F52E420DA7F4D00C9F612 = {
isa = PBXGroup;
children = (
FCBF210520DC007900B5FDF0 /* paddle_mobile.framework */,
FCBF20FC20DBFF4D00B5FDF0 /* SwiftProtobuf.framework */,
FC9F52EF20DA7F4D00C9F612 /* paddle-mobile-demo */,
FC9F52EE20DA7F4D00C9F612 /* Products */,
FCBF20F520DBFE7300B5FDF0 /* Frameworks */,
);
sourceTree = "<group>";
};
FC9F52EE20DA7F4D00C9F612 /* Products */ = {
isa = PBXGroup;
children = (
FC9F52ED20DA7F4D00C9F612 /* paddle-mobile-demo.app */,
);
name = Products;
sourceTree = "<group>";
};
FC9F52EF20DA7F4D00C9F612 /* paddle-mobile-demo */ = {
isa = PBXGroup;
children = (
FC111BE020DE079E00F213F8 /* yolo */,
FC111A6520DD31C700F213F8 /* test.pb.swift */,
FC9F52F020DA7F4D00C9F612 /* AppDelegate.swift */,
FC9F52F220DA7F4D00C9F612 /* ViewController.swift */,
FC9F52F420DA7F4D00C9F612 /* Main.storyboard */,
FC9F52F720DA7F4F00C9F612 /* Assets.xcassets */,
FC9F52F920DA7F4F00C9F612 /* LaunchScreen.storyboard */,
FC9F52FC20DA7F4F00C9F612 /* Info.plist */,
);
path = "paddle-mobile-demo";
sourceTree = "<group>";
};
FCBF20F520DBFE7300B5FDF0 /* Frameworks */ = {
isa = PBXGroup;
children = (
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
FC9F52EC20DA7F4D00C9F612 /* paddle-mobile-demo */ = {
isa = PBXNativeTarget;
buildConfigurationList = FC9F52FF20DA7F4F00C9F612 /* Build configuration list for PBXNativeTarget "paddle-mobile-demo" */;
buildPhases = (
FC9F52E920DA7F4D00C9F612 /* Sources */,
FC9F52EA20DA7F4D00C9F612 /* Frameworks */,
FC9F52EB20DA7F4D00C9F612 /* Resources */,
FCBF210420DC005100B5FDF0 /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = "paddle-mobile-demo";
productName = "paddle-mobile-demo";
productReference = FC9F52ED20DA7F4D00C9F612 /* paddle-mobile-demo.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
FC9F52E520DA7F4D00C9F612 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0930;
LastUpgradeCheck = 0930;
ORGANIZATIONNAME = orange;
TargetAttributes = {
FC9F52EC20DA7F4D00C9F612 = {
CreatedOnToolsVersion = 9.3.1;
};
};
};
buildConfigurationList = FC9F52E820DA7F4D00C9F612 /* Build configuration list for PBXProject "paddle-mobile-demo" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = FC9F52E420DA7F4D00C9F612;
productRefGroup = FC9F52EE20DA7F4D00C9F612 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
FC9F52EC20DA7F4D00C9F612 /* paddle-mobile-demo */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
FC9F52EB20DA7F4D00C9F612 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
FC9F52FB20DA7F4F00C9F612 /* LaunchScreen.storyboard in Resources */,
FC111BE420DE079E00F213F8 /* model in Resources */,
FC9F52F820DA7F4F00C9F612 /* Assets.xcassets in Resources */,
FC111BE320DE079E00F213F8 /* params in Resources */,
FC9F52F620DA7F4D00C9F612 /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
FC9F52E920DA7F4D00C9F612 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
FC9F52F320DA7F4D00C9F612 /* ViewController.swift in Sources */,
FC111A6620DD31C700F213F8 /* test.pb.swift in Sources */,
FC9F52F120DA7F4D00C9F612 /* AppDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
FC9F52F420DA7F4D00C9F612 /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
FC9F52F520DA7F4D00C9F612 /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
FC9F52F920DA7F4F00C9F612 /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
FC9F52FA20DA7F4F00C9F612 /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
FC9F52FD20DA7F4F00C9F612 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.3;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
FC9F52FE20DA7F4F00C9F612 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.3;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
FC9F530020DA7F4F00C9F612 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = Z5M2UUN5YV;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)",
);
INFOPLIST_FILE = "paddle-mobile-demo/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "orange.paddle-mobile-demo";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
FC9F530120DA7F4F00C9F612 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = Z5M2UUN5YV;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)",
);
INFOPLIST_FILE = "paddle-mobile-demo/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "orange.paddle-mobile-demo";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
FC9F52E820DA7F4D00C9F612 /* Build configuration list for PBXProject "paddle-mobile-demo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
FC9F52FD20DA7F4F00C9F612 /* Debug */,
FC9F52FE20DA7F4F00C9F612 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
FC9F52FF20DA7F4F00C9F612 /* Build configuration list for PBXNativeTarget "paddle-mobile-demo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
FC9F530020DA7F4F00C9F612 /* Debug */,
FC9F530120DA7F4F00C9F612 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = FC9F52E520DA7F4D00C9F612 /* Project object */;
}
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:paddle-mobile-demo.xcodeproj">
</FileRef>
</Workspace>
<?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>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
<?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>SchemeUserState</key>
<dict>
<key>paddle-mobile-demo.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>2</integer>
</dict>
</dict>
</dict>
</plist>
//
// AppDelegate.swift
// paddle-mobile-demo
//
// Created by liuRuiLong on 2018/6/20.
// Copyright © 2018年 orange. All rights reserved.
//
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
\ No newline at end of file
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" systemVersion="17A277" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" systemVersion="17A277" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
<?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>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
//
// ViewController.swift
// paddle-mobile-demo
//
// Created by liuRuiLong on 2018/6/20.
// Copyright © 2018年 orange. All rights reserved.
//
import UIKit
import paddle_mobile
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var date = Date.init()
if let modelPath = Bundle.main.path(forResource: "model", ofType: nil), let paraPath = Bundle.main.path(forResource: "params", ofType: nil) {
print(" bundlepath: " + modelPath)
let loader = Loader<Float32>.init()
try! loader.load(modelPath: modelPath, paraPath: paraPath)
}
let els = Date.init().timeIntervalSince(date)
print(els)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
// DO NOT EDIT.
//
// Generated by the Swift generator plugin for the protocol buffer compiler.
// Source: test.proto
//
// For information on using the generated types, please see the documenation:
// https://github.com/apple/swift-protobuf/
import Foundation
import SwiftProtobuf
// If the compiler emits an error on this type, it is because this file
// was generated by a version of the `protoc` Swift plug-in that is
// incompatible with the version of SwiftProtobuf to which you are linking.
// Please ensure that your are building against the same version of the API
// that was used to generate this file.
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
typealias Version = _2
}
struct BookInfo {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var id: Int64 = 0
var title: String = String()
var author: String = String()
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
// MARK: - Code below here is support for the SwiftProtobuf runtime.
extension BookInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = "BookInfo"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "id"),
2: .same(proto: "title"),
3: .same(proto: "author"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularInt64Field(value: &self.id)
case 2: try decoder.decodeSingularStringField(value: &self.title)
case 3: try decoder.decodeSingularStringField(value: &self.author)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.id != 0 {
try visitor.visitSingularInt64Field(value: self.id, fieldNumber: 1)
}
if !self.title.isEmpty {
try visitor.visitSingularStringField(value: self.title, fieldNumber: 2)
}
if !self.author.isEmpty {
try visitor.visitSingularStringField(value: self.author, fieldNumber: 3)
}
try unknownFields.traverse(visitor: &visitor)
}
func _protobuf_generated_isEqualTo(other: BookInfo) -> Bool {
if self.id != other.id {return false}
if self.title != other.title {return false}
if self.author != other.author {return false}
if unknownFields != other.unknownFields {return false}
return true
}
}
platform :ios, 9.0
use_frameworks!
target 'paddle-mobile-demo' do
pod 'SwiftProtobuf', '~> 1.0'
end
target 'paddle-mobile' do
pod 'SwiftProtobuf', '~> 1.0'
end
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:paddle-mobile.xcodeproj">
</FileRef>
</Workspace>
<?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>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
<?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>SchemeUserState</key>
<dict>
<key>paddle-mobile.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>3</integer>
</dict>
</dict>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:../../example/paddle-mobile-demo/paddle-mobile-demo.xcodeproj">
</FileRef>
<FileRef
location = "group:paddle-mobile.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>
<?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>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
type = "0"
version = "2.0">
</Bucket>
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Foundation
public enum PaddleMobileError: Error{
case loaderError(message: String)
case netError(message: String)
case memoryError(message: String)
case paramError(message: String)
}
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Foundation
// 自定义 ?! 如果 ?! 前的返回值为一个可选值, 则进行隐式解包, 如果有值则返回这个值, 如果为nil 则fatalError 传入的信息
precedencegroup ExecutedOrFatalError{
associativity: left
higherThan: AssignmentPrecedence
}
infix operator ?!: ExecutedOrFatalError
func ?!<T>(option: T?, excuteOrError: @autoclosure () -> String) -> T{
if let inOpt = option {
return inOpt
}else{
fatalError(excuteOrError())
}
}
//Lense
struct Lense<A, B> {
let from: (A) -> B
let to: (B, A) -> A
}
precedencegroup CombineLense{
associativity: left
higherThan: AssignmentPrecedence
}
infix operator >>>: CombineLense
func >>><A, B, C>(left: Lense<B, C>, right: Lense<A, B>) -> Lense<A, C> {
return Lense<A, C>.init(from: { (a) -> C in
left.from(right.from(a))
}, to: { (c, a) -> A in
right.to( left.to(c, right.from(a)),a)
})
}
protocol CIntIndex {
associatedtype T;
subscript(index: CInt) -> T { get set};
}
extension Array: CIntIndex{
typealias T = Element
subscript(index: CInt) -> T {
get{
guard Int64(Int.max) >= Int64(index) else{
fatalError("cint index out of Int range")
}
return self[Int(index)]
}
set{
guard Int64(Int.max) >= Int64(index) else{
fatalError("cint index out of Int range")
}
self[Int(index)] = newValue
}
}
}
//MARK: Array extension
extension Array where Element: Comparable{
/// 返回数组前 r 个元素, 并将元素处于原数组的位置作为元组的第一个元素返回
///
/// - Parameter r: 前 r 个元素
/// - Returns: [(原有位置, 排好位置的元素)]
func top(r: Int) -> [(Int, Element)] {
precondition(r <= self.count)
return Array<(Int, Element)>(zip(0..<self.count, self).sorted{ $0.1 > $1.1 }.prefix(through: r - 1))
}
}
extension String{
func cStr() -> UnsafePointer<Int8>? {
return (self as NSString).utf8String
}
}
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Foundation
//typealias Float16 = Int16
//extension Float16: PrecisionType {
//}
public protocol PrecisionType {
}
extension Float32: PrecisionType {
}
enum DataLayout {
case NCHW
case NHWC
}
protocol Variant {
}
extension Tensor: Variant {
}
let gConvType = "conv2d"
let gBatchNormType = "batch_norm"
let gReluType = "relu"
let gElementwiseAdd = "elementwise_add"
let opInputsOutputsKey = [gConvType : (inputs: ["Input"], outputs: ["Output"]),
gBatchNormType : (inputs: ["X"], outputs: ["Y"]),
gReluType : (inputs: ["X"], outputs: ["Out"]),
gElementwiseAdd : (inputs: ["X", "Y"], outputs: ["Out"])]
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Foundation
class Executor {
}
<?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>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Foundation
import SwiftProtobuf
class ParamData<P: PrecisionType> {
let size: Int
var dim: Dim
private(set) var layout: DataLayout
var pointer: UnsafeMutablePointer<P>
init(inDim: Dim, inLayout: DataLayout = .NCHW) {
dim = inDim
size = inDim.numel() * MemoryLayout<P>.size
pointer = UnsafeMutablePointer<P>.allocate(capacity: size)
layout = inLayout
}
func convert(to: DataLayout) {
guard to != layout else {
return
}
guard dim.cout() == 4 else {
return
}
guard layout == .NCHW && to == .NHWC else {
// other not support
return
}
let newPointer = UnsafeMutablePointer<P>.allocate(capacity: size)
if layout == .NCHW {
NCHW2NHWC(newPtr: newPointer)
}
pointer.deinitialize(count: size)
pointer.deallocate()
pointer = newPointer
layout = to
}
func NCHW2NHWC(newPtr: UnsafeMutablePointer<P>) {
let N = dim[0]
let C = dim[1]
let H = dim[2]
let W = dim[3]
let HXW = H * W
let CXHXW = C * H * W
var index: Int = 0
for n in 0..<N {
for h in 0..<H{
for w in 0..<W{
for c in 0..<C{
newPtr[index] = pointer[n * CXHXW + c * HXW + h * w + w]
index += 1
}
}
}
}
dim.swapeDimAt(index1: 1, index2: 3)
}
deinit {
pointer.deinitialize(count: size)
pointer.deallocate()
}
}
public class Loader<P: PrecisionType> {
class ParaLoader {
let file: UnsafeMutablePointer<FILE>
let fileSize: Int
var nowIndex: Int
init(paramPath: String) throws {
guard let tmpFile = fopen(paramPath, "rb") else {
throw PaddleMobileError.loaderError(message: "open param file error" + paramPath)
}
file = tmpFile
fseek(file, 0, SEEK_END)
fileSize = ftell(file)
guard fileSize > 0 else {
throw PaddleMobileError.loaderError(message: "param file size is too small")
}
rewind(file)
nowIndex = 0
}
func read(data: ParamData<P>) throws {
guard nowIndex <= fileSize else {
throw PaddleMobileError.loaderError(message: "out of the file range")
}
func pointerReader<T>(type: T.Type) -> T {
let ptr = UnsafeMutablePointer<T>.allocate(capacity: MemoryLayout<T>.size)
fread(ptr, 1, MemoryLayout<T>.size, file)
nowIndex += MemoryLayout<T>.size
let pointee = ptr.pointee
ptr.deinitialize(count: MemoryLayout<UInt32>.size)
ptr.deallocate()
return pointee
}
_ = pointerReader(type: UInt32.self)
let lodLevel = pointerReader(type: UInt64.self)
for _ in 0..<lodLevel {
let size = pointerReader(type: UInt64.self)
for _ in 0..<Int(size/UInt64(MemoryLayout<size_t>.size)){
_ = pointerReader(type: size_t.self)
}
}
let _ = pointerReader(type: UInt32.self)
let tensorDescSize = pointerReader(type: Int32.self)
fseek(file, Int(tensorDescSize), SEEK_CUR)
nowIndex += Int(tensorDescSize)
/*
这里没有根据 Data Type 去判断, 而是从外部泛型直接指定了精度
*/
let bytesRead = fread(data.pointer, 1, data.size, file)
guard bytesRead == data.size else {
throw PaddleMobileError.loaderError(message: "param read size error")
}
nowIndex += bytesRead
}
deinit {
fclose(file)
}
}
public init(){}
public func load(modelPath: String, paraPath: String) throws -> Program{
guard let modelData = try? Data.init(contentsOf: URL.init(fileURLWithPath: modelPath)) else {
throw PaddleMobileError.loaderError(message: "load " + modelPath + " failed !")
}
do {
let protoProgram = try PaddleMobile_Framework_Proto_ProgramDesc.init(
serializedData: modelData)
let scope = Scope.init()
let program = Program.init(protoProgramDesc: protoProgram, inParamPath: paraPath, inScope: scope)
guard let paraLoader = try? ParaLoader.init(paramPath: paraPath) else {
throw PaddleMobileError.loaderError(message: "load para error")
}
for block in program.programDesc.blocks {
for varDesc in block.vars {
if (varDesc.type == .LodTensor) {
if (varDesc.persistable
&& varDesc.type != .FeedMiniBatch
&& varDesc.type != .FetchList) {
guard let tensorDesc = varDesc.tensorDesc else {
throw PaddleMobileError.loaderError(message: "get tensor desc failed")
}
guard (try? tensorDesc.dataType.dataTypeSize()) == MemoryLayout<P>.size else {
throw PaddleMobileError.memoryError(message: "PrecisionType not support")
}
let dimArr = tensorDesc.dims
guard dimArr.count > 0 else {
throw PaddleMobileError.loaderError(message: "tensor desc dim size error")
}
let dim = Dim.init(inDim: dimArr)
let paraData = ParamData<P>.init(inDim: dim)
do {
try paraLoader.read(data: paraData)
} catch let error {
throw error
}
paraData.convert(to: .NHWC)
let tensor = Tensor<P>.init(inData: paraData)
scope.vars[varDesc.name] = tensor
}
}
}
}
return program
} catch _ {
throw PaddleMobileError.loaderError(message: "protobuf decoder error")
}
}
}
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Foundation
struct BatchNormParam<P: PrecisionType>: Param {
typealias ParamP = P
init(opDesc: OpDesc, scope: Scope) throws {
do {
inputX = try BatchNormParam.inputX(inputs: opDesc.inputs, from: scope)
outputY = try BatchNormParam.outputY(outputs: opDesc.outputs, from: scope)
inputBias = try BatchNormParam.inputBiase(inputs: opDesc.paraInputs, from: scope)
inputMean = try BatchNormParam.inputMean(inputs: opDesc.paraInputs, from: scope)
inputScale = try BatchNormParam.inputScale(inputs: opDesc.paraInputs, from: scope)
inputVariance = try BatchNormParam.inputVariance(inputs: opDesc.paraInputs, from: scope)
epsilon = try BatchNormParam.getAttr(key: "epsilon", attrs: opDesc.attrs)
momentum = try BatchNormParam.getAttr(key: "momentum", attrs: opDesc.attrs)
is_test = try BatchNormParam.getAttr(key: "is_test", attrs: opDesc.attrs)
} catch let error {
throw error
}
}
let inputX: Tensor<ParamP>
let outputY: Tensor<ParamP>
let inputBias: Tensor<ParamP>
let inputMean: Tensor<ParamP>
let inputScale: Tensor<ParamP>
let inputVariance: Tensor<ParamP>
let epsilon: Float
let momentum: Float
let is_test: Bool
}
class BatchNormOp<P: PrecisionType>: Operator<BatchNormParam<P>> {
}
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Foundation
struct ConvParam<P: PrecisionType>: Param {
typealias ParamP = P
init(opDesc: OpDesc, scope: Scope) throws {
do {
filter = try ConvParam.inputFilter(paraInputs: opDesc.paraInputs, from: scope)
input = try ConvParam.input(inputs: opDesc.inputs, from: scope)
output = try ConvParam.output(outputs: opDesc.outputs, from: scope)
stride = try ConvParam.getAttr(key: "stride", attrs: opDesc.attrs)
paddings = try ConvParam.getAttr(key: "paddings", attrs: opDesc.attrs)
dilations = try ConvParam.getAttr(key: "dilations", attrs: opDesc.attrs)
groups = try ConvParam.getAttr(key: "groups", attrs: opDesc.attrs)
} catch let error {
throw error
}
}
let input: Tensor<ParamP>
let output: Tensor<ParamP>
let filter: Tensor<ParamP>
let stride: [Int]
let paddings: [Int]
let dilations: [Int]
let groups: Int
}
class ConvOp<P: PrecisionType>: Operator<ConvParam<P>> {
override func runImpl() {
}
}
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Foundation
struct ElementwiseAddParam<P: PrecisionType>: Param {
typealias ParamP = P
init(opDesc: OpDesc, scope: Scope) throws {
do {
inputX = try ElementwiseAddParam.inputX(inputs: opDesc.inputs, from: scope)
inputY = try ElementwiseAddParam.inputY(inputs: opDesc.inputs, from: scope)
out = try ElementwiseAddParam.outputOut(outputs: opDesc.outputs, from: scope)
axis = try ElementwiseAddParam.getAttr(key: "axis", attrs: opDesc.attrs)
} catch let error {
throw error
}
}
let inputX: Tensor<P>
let inputY: Tensor<P>
let out: Tensor<P>
let axis: Int
}
class ElementwiseAddOp<P: PrecisionType>: Operator<ElementwiseAddParam<P>>{
override func runImpl() {
}
}
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Foundation
/*
let opInputsOutputsKey = [gConvType : (inputs: ["Input"], outputs: ["Output"]),
gBatchNormType : (inputs: ["X"], outputs: ["Y"]),
gReluType : (inputs: ["X"], outputs: ["Out"]),
gElementwiseAdd : (inputs: ["X", "Y"], outputs: ["Out"])]
*/
protocol Param {
associatedtype ParamP: PrecisionType
init(opDesc: OpDesc, scope: Scope) throws
static func getFirstTensor(key: String, map: [String : [String]], from: Scope) throws -> Tensor<ParamP>
static func inputX(inputs: [String : [String]], from: Scope) throws -> Tensor<ParamP>
static func inputBiase(inputs: [String : [String]], from: Scope) throws -> Tensor<ParamP>
static func inputMean(inputs: [String : [String]], from: Scope) throws -> Tensor<ParamP>
static func inputScale(inputs: [String : [String]], from: Scope) throws -> Tensor<ParamP>
static func inputVariance(inputs: [String : [String]], from: Scope) throws -> Tensor<ParamP>
static func inputFilter(paraInputs: [String : [String]], from: Scope) throws -> Tensor<ParamP>
static func input(inputs: [String : [String]], from: Scope) throws -> Tensor<ParamP>
static func output(outputs: [String : [String]], from: Scope) throws -> Tensor<ParamP>
static func outputY(outputs: [String : [String]], from: Scope) throws -> Tensor<ParamP>
static func inputY(inputs: [String : [String]], from: Scope) throws -> Tensor<ParamP>
static func outputOut(outputs: [String : [String]], from: Scope) throws -> Tensor<ParamP>
static func getAttr<T>(key: String, attrs: [String : Attr]) throws -> T
}
extension Param {
static func getFirstTensor(key: String, map: [String : [String]], from: Scope) throws -> Tensor<ParamP> {
guard let mapKeys = map["X"], mapKeys.count > 0, let inputX = from[mapKeys[0]], let tensorX = inputX as? Tensor<ParamP> else {
throw PaddleMobileError.paramError(message: "tensor " + key + "in \(map) not found")
}
return tensorX
}
static func inputX(inputs: [String : [String]], from: Scope) throws -> Tensor<ParamP> {
do {
let tensorX = try getFirstTensor(key: "X", map: inputs, from: from)
return tensorX
} catch let error {
throw error
}
}
static func input(inputs: [String : [String]], from: Scope) throws -> Tensor<ParamP> {
do {
let tensorInput = try getFirstTensor(key: "Input", map: inputs, from: from)
return tensorInput
} catch let error {
throw error
}
}
static func output(outputs: [String : [String]], from: Scope) throws -> Tensor<ParamP> {
do {
let tensorOutput = try getFirstTensor(key: "Output", map: outputs, from: from)
return tensorOutput
} catch let error {
throw error
}
}
static func outputY(outputs: [String : [String]], from: Scope) throws -> Tensor<ParamP> {
do {
let tensorOutputY = try getFirstTensor(key: "Y", map: outputs, from: from)
return tensorOutputY
} catch let error {
throw error
}
}
static func inputY(inputs: [String : [String]], from: Scope) throws -> Tensor<ParamP> {
do {
let tensorY = try getFirstTensor(key: "Y", map: inputs, from: from)
return tensorY
} catch let error {
throw error
}
}
static func outputOut(outputs: [String : [String]], from: Scope) throws -> Tensor<ParamP> {
do {
let out = try getFirstTensor(key: "Out", map: outputs, from: from)
return out
} catch let error {
throw error
}
}
static func inputFilter(paraInputs: [String : [String]], from: Scope) throws -> Tensor<ParamP> {
do {
let tensorFilter = try getFirstTensor(key: "Filter", map: paraInputs, from: from)
return tensorFilter
} catch let error {
throw error
}
}
static func inputBiase(inputs: [String : [String]], from: Scope) throws -> Tensor<ParamP> {
do {
let tensorBias = try getFirstTensor(key: "Bias", map: inputs, from: from)
return tensorBias
} catch let error {
throw error
}
}
static func inputMean(inputs: [String : [String]], from: Scope) throws -> Tensor<ParamP> {
do {
let tensorMean = try getFirstTensor(key: "Mean", map: inputs, from: from)
return tensorMean
} catch let error {
throw error
}
}
static func inputScale(inputs: [String : [String]], from: Scope) throws -> Tensor<ParamP> {
do {
let tensorScale = try getFirstTensor(key: "Scale", map: inputs, from: from)
return tensorScale
} catch let error {
throw error
}
}
static func inputVariance(inputs: [String : [String]], from: Scope) throws -> Tensor<ParamP> {
do {
let tensorVariance = try getFirstTensor(key: "Variance", map: inputs, from: from)
return tensorVariance
} catch let error {
throw error
}
}
static func getAttr<T>(key: String, attrs: [String : Attr]) throws -> T{
guard let attr = attrs[key] as? T else {
throw PaddleMobileError.paramError(message: "attr type error")
}
return attr
}
}
class Operator<ParamType: Param> {
let type: String
let inputs: [String : [String]]
let paraInputs: [String : [String]]
let outpus: [String : [String]]
let attrs: [String : Attr]
let para: ParamType
init(opDesc: OpDesc, inScope: Scope) throws {
type = opDesc.type
inputs = opDesc.inputs
outpus = opDesc.outputs
attrs = opDesc.attrs
paraInputs = opDesc.paraInputs
do {
para = try ParamType.init(opDesc:opDesc, scope: inScope)
} catch let error {
throw error
}
}
func run() {
runImpl()
}
func runImpl() {
fatalError("runimpl of " + type + "op not implement")
}
}
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Foundation
struct ReluParam<P: PrecisionType>: Param {
typealias ParamP = P
init(opDesc: OpDesc, scope: Scope) throws {
do {
inputX = try ReluParam.inputX(inputs: opDesc.inputs, from: scope)
out = try ReluParam.outputOut(outputs: opDesc.outputs, from: scope)
} catch let error {
throw error
}
}
let inputX: Tensor<ParamP>
let out: Tensor<ParamP>
}
class ReluOp<P: PrecisionType>: Operator<ReluParam<P>> {
override func runImpl() {
}
}
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Foundation
protocol Attr {
}
extension Bool: Attr {
}
extension Int: Attr {
}
extension Float: Attr {
}
extension Int64: Attr {
}
extension Array: Attr {
}
func attrWithProtoDesc(attrDesc: PaddleMobile_Framework_Proto_OpDesc.Attr) -> Attr {
switch attrDesc.type {
case .boolean:
return attrDesc.b
case .int:
return Int(attrDesc.i)
case .string:
return attrDesc.strings
case .long:
return attrDesc.l
case .float:
return attrDesc.f
case .booleans:
return attrDesc.bools
case .floats:
return attrDesc.floats
case .ints:
return attrDesc.ints
case .strings:
return attrDesc.strings
default:
fatalError(" not support this attr type: \(attrDesc.type)")
}
}
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Foundation
struct BlockDesc {
let index: Int
let parentIndex: Int
let vars: [VarDesc]
let ops: [OpDesc]
init(block: PaddleMobile_Framework_Proto_BlockDesc) {
index = Int(block.idx)
parentIndex = Int(block.parentIdx)
var vars: [VarDesc] = []
for varOfBlock in block.vars {
vars.append(VarDesc.init(protoVarDesc: varOfBlock))
}
vars.sort { $0.name < $1.name }
self.vars = vars
var ops: [OpDesc] = []
for op in block.ops {
ops.append(OpDesc.init(protoOpDesc: op))
}
self.ops = ops
}
}
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Foundation
struct OpDesc {
let inputs: [String : [String]]
let paraInputs: [String : [String]]
let outputs: [String : [String]]
let unusedOutputs: [String : [String]]
var attrs: [String : Attr] = [:]
let type: String
init(protoOpDesc: PaddleMobile_Framework_Proto_OpDesc) {
type = protoOpDesc.type
let creator = { (vars: [PaddleMobile_Framework_Proto_OpDesc.Var], canAdd: (String) -> Bool) -> [String : [String]] in
var map: [String : [String]] = [:]
for opDescVar in vars {
if (canAdd(opDescVar.parameter)) {
map[opDescVar.parameter] = opDescVar.arguments
}
}
return map
}
inputs = creator(protoOpDesc.inputs) {
opInputsOutputsKey[protoOpDesc.type]?.inputs.contains($0) ?? false
}
paraInputs = creator(protoOpDesc.inputs) {
!(opInputsOutputsKey[protoOpDesc.type]?.inputs.contains($0) ?? false)
}
outputs = creator(protoOpDesc.outputs) {
opInputsOutputsKey[protoOpDesc.type]?.outputs.contains($0) ?? false
}
unusedOutputs = creator(protoOpDesc.outputs) {
!(opInputsOutputsKey[protoOpDesc.type]?.outputs.contains($0) ?? false)
}
for attr in protoOpDesc.attrs {
if (attr.type != .block) {
attrs[attr.name] = attrWithProtoDesc(attrDesc: attr)
}
}
}
}
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Foundation
public struct Program {
let paramPath: String
let programDesc: ProgramDesc
let scope: Scope
init(protoProgramDesc: PaddleMobile_Framework_Proto_ProgramDesc, inParamPath: String, inScope: Scope) {
programDesc = ProgramDesc.init(protoProgram: protoProgramDesc)
paramPath = inParamPath
scope = inScope
}
}
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Foundation
public struct ProgramDesc {
var blocks: [BlockDesc] = []
init(protoProgram: PaddleMobile_Framework_Proto_ProgramDesc) {
for block in protoProgram.blocks {
self.blocks.append(BlockDesc.init(block: block))
}
}
}
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Foundation
class Scope {
var vars: [String : Variant] = [:]
subscript(key: String) -> Variant?{
return vars[key]
}
}
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Foundation
struct TensorDesc {
let dims: [Int]
let dataType: VarTypeType
init(protoTensorDesc: PaddleMobile_Framework_Proto_VarType.TensorDesc) {
dims = protoTensorDesc.dims.map{ Int($0)}
dataType = VarTypeType.init(rawValue: protoTensorDesc.dataType.rawValue) ?? .ErrorType
}
}
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Foundation
enum VarTypeType: Int {
case ErrorType = -1,
Bool = 0,
Int16 = 1,
Int32 = 2,
Int64 = 3,
FP16 = 4,
FP32 = 5,
FP64 = 6,
LodTensor = 7,
SelectedRows = 8,
FeedMiniBatch = 9,
FetchList = 10,
StepScopes = 11,
StepLodRankTable = 12,
StepLodTensorArray = 13,
StepPlaceList = 14,
Reader = 15,
Channel = 16,
Raw = 17,
Tuple = 18
func dataTypeSize() throws -> Int {
switch self {
case .FP16:
return 2
case .FP32:
return 4
case .FP64:
return 8
case .Int32:
return 4
case .Int64:
return 8
case .Bool:
return 1
default:
throw PaddleMobileError.memoryError(message: "not support \(self) type to get size ")
}
}
}
struct VarDesc {
let name: String
let persistable: Bool
let type: VarTypeType
let tensorDesc: TensorDesc?
init(protoVarDesc: PaddleMobile_Framework_Proto_VarDesc) {
type = VarTypeType.init(rawValue: protoVarDesc.type.type.rawValue) ?? .ErrorType
name = protoVarDesc.name
persistable = protoVarDesc.persistable
switch type {
case .SelectedRows:
tensorDesc = TensorDesc.init(protoTensorDesc: protoVarDesc.type.selectedRows)
case .LodTensor:
tensorDesc = TensorDesc.init(protoTensorDesc: protoVarDesc.type.lodTensor.tensor)
case .StepLodTensorArray:
tensorDesc = TensorDesc.init(protoTensorDesc: protoVarDesc.type.tensorArray.tensor);
default:
tensorDesc = .none
}
}
}
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Foundation
struct Dim {
init(inDim: [Int]) {
dims = inDim
}
mutating func swapeDimAt(index1: Int, index2: Int) {
dims.swapAt(index1, index2)
}
func cout() -> Int {
return dims.count
}
func numel() -> Int {
return dims.reduce(1) { $0 * $1 }
}
static func ==(left: Dim, right: Dim) -> Bool {
return left.dims == right.dims;
}
subscript(index: Int) -> Int {
return dims[index];
}
private var dims: [Int]
private init(){
fatalError()
}
}
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Foundation
class Tensor <P: PrecisionType>{
var dim: Dim {
return paraData.dim
}
let paraData: ParamData<P>
init(inDimArray: [Int], inData: ParamData<P>) {
paraData = inData
}
init(inData: ParamData<P>) {
paraData = inData
}
func numel() -> Int {
return dim.numel()
}
func dataLayout() -> DataLayout {
return paraData.layout
}
}
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
#import <UIKit/UIKit.h>
//! Project version number for paddle_mobile.
FOUNDATION_EXPORT double paddle_mobileVersionNumber;
//! Project version string for paddle_mobile.
FOUNDATION_EXPORT const unsigned char paddle_mobileVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <paddle_mobile/PublicHeader.h>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册