Determine if iOS device is 32- or 64-bit - ios

Does anyone know of an easy way to tell if an iOS7 device has 32- or 64-bit hardware? I don't mean programmatically, I just mean via settings, model number, 3rd-party app, etc.
I'm having a problem that I suspect is 64-bit related. Apple's advice is to test on the 64-bit simulator but also on an actual 64-bit device, but then doesn't say anything about how to determine that. I can write a test app to check sizeof(int) or whatever, but there's got to be some way for, say, tech support to know what they're working with.
Eric

There is no other "official" way to determine it. You can determine it using this code:
if (sizeof(void*) == 4) {
NSLog(#"32-bit App");
} else if (sizeof(void*) == 8) {
NSLog(#"64-bit App");
}

Below is the method is64bitHardware. It returns YES if the hardware is a 64-bit hardware and works on a real iOS device and in an iOS Simulator. Here is source.
#include <mach/mach.h>
+ (BOOL) is64bitHardware
{
#if __LP64__
// The app has been compiled for 64-bit intel and runs as 64-bit intel
return YES;
#endif
// Use some static variables to avoid performing the tasks several times.
static BOOL sHardwareChecked = NO;
static BOOL sIs64bitHardware = NO;
if(!sHardwareChecked)
{
sHardwareChecked = YES;
#if TARGET_IPHONE_SIMULATOR
// The app was compiled as 32-bit for the iOS Simulator.
// We check if the Simulator is a 32-bit or 64-bit simulator using the function is64bitSimulator()
// See http://blog.timac.org/?p=886
sIs64bitHardware = is64bitSimulator();
#else
// The app runs on a real iOS device: ask the kernel for the host info.
struct host_basic_info host_basic_info;
unsigned int count;
kern_return_t returnValue = host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)(&host_basic_info), &count);
if(returnValue != KERN_SUCCESS)
{
sIs64bitHardware = NO;
}
sIs64bitHardware = (host_basic_info.cpu_type == CPU_TYPE_ARM64);
#endif // TARGET_IPHONE_SIMULATOR
}
return sIs64bitHardware;
}

Totally untested, but you should be able to get the CPU via sysctl like this:
#include <sys/types.h>
#include <sys/sysctl.h>
#include <mach/machine.h>
void foo() {
size_t size;
cpu_type_t type;
size = sizeof(type);
sysctlbyname("hw.cputype", &type, &size, NULL, 0);
if (type == CPU_TYPE_ARM64) {
// ARM 64-bit CPU
} else if (type == CPU_TYPE_ARM) {
// ARM 32-bit CPU
} else {
// Something else.
}
}
In the iOS 7 SDK, CPU_TYPE_ARM64 is defined in <mach/machine.h> as:
#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64)
A different way seems to be:
#include <mach/mach_host.h>
void foo() {
host_basic_info_data_t hostInfo;
mach_msg_type_number_t infoCount;
infoCount = HOST_BASIC_INFO_COUNT;
host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo, &infoCount);
if (hostInfo.cpu_type == CPU_TYPE_ARM64) {
// ARM 64-bit CPU
} else if (hostInfo.cpu_type == CPU_TYPE_ARM) {
// ARM 32-bit CPU
} else {
// Something else.
}
}

If you are compiling with clang, there is another way: just check if __arm__ or __arm64__ is defined.
The example code below is not tested but it should illustrate what I mean by that:
#if defined(__arm__)
NSLog(#"32-bit App");
#elif defined(__arm64__)
NSLog(#"64-bit App");
#else
NSLog(#"Not running ARM");
#endif
Note that this relies on the fact that current iOS application binaries contain both, 32bit and 64bit binaries in a single container and they will be correctly selected depending on whether your app supports executing 64bit.

You can use bitWidth on Int
https://developer.apple.com/documentation/swift/int/2885648-bitwidth
static var is32Bit: Bool {
return Int.bitWidth == 32
}
static var is64Bit: Bool {
return Int.bitWidth == 64
}

I use this in swift 4, not sure if it's the best solution but it works.
func getCPUArch()
{
#if arch(arm)
print("this is a 32bit system")
#elseif arch(arm64)
print("this is a 64bit system")
#endif
}

In runtime you can use something like this
extension UIDevice {
static let is64Bit = MemoryLayout<Int>.size == MemoryLayout<Int64>.size
}

Related

How to compile two versions of metal files

I want to support both 10.13 and 10.14 however I want to support fast math on 10.14. I am only able to compile project if I force #define __CIKERNEL_METAL_VERSION__ 200 but this means on 10.13 it will crash. How do I configure the project so it creates 2 metal libraries? So far the result file is default.metallib (compiling using Xcode)
BOOL supportsMetal;
#if TARGET_OS_IOS
supportsMetal = MTLCreateSystemDefaultDevice() != nil; //this forces GPU on macbook to switch immediatelly
#else
supportsMetal = [MTLCopyAllDevices() count] >= 1;
#endif
if (#available(macOS 10.13, *)) {
//only 10.14 fully supports metal with fast math, however there are hackintoshes etc...
if (supportsMetal) {
_kernel = [self metalKernel];
} else {
_kernel = [self GLSLKernel];
}
} else {
_kernel = [self GLSLKernel];
}
if (_kernel == nil) return nil;
METAL file
#include <metal_stdlib>
using namespace metal;
//https://en.wikipedia.org/wiki/List_of_monochrome_and_RGB_palettes
//https://en.wikipedia.org/wiki/Relative_luminance
//https://en.wikipedia.org/wiki/Grayscale
//<CoreImage/CIKernelMetalLib.h>
//only if you enable fast math (macOS10.14 or iOS12) otherwise fall back to float4 instead of half4
//forcing compilation for macOS 10.14+//iOS12+
#define __CIKERNEL_METAL_VERSION__ 200
constant half3 kRec709Luma = half3(0.2126, 0.7152, 0.0722);
constant half3 kRec601Luma = half3(0.299 , 0.587 , 0.114);
//constant float3 kRec2100Luma = float3(0.2627, 0.6780, 0.0593);
#include <CoreImage/CoreImage.h>
extern "C" { namespace coreimage {
float lumin601(half3 p)
{
return dot(p.rgb, kRec601Luma);
}
float lumin709(half3 p)
{
return dot(p.rgb, kRec709Luma);
}
half4 thresholdFilter(sample_h image, float threshold)
{
half4 pix = unpremultiply(image);
float luma = lumin601(pix.rgb);
pix.rgb = half3(step(threshold, luma));
return premultiply(pix);
}
}}
XCode 11 supports Metal libraries.
Add a new build target to your project.
Add metal files in compile sources
If you use Core Image add these linker flags. Change deployment targets (ios12+ ) and check for fast math.
To your original project target add new dependencies and copy script
cp "${BUILT_PRODUCTS_DIR}"/*.metallib "${METAL_LIBRARY_OUTPUT_DIR}"
Optional:
Avoiding hard coded strings everywhere in project. Add xconfig file to project
MY_METAL_LIBRARY_NAME_10_13 = Metal_10_13_aaa
MY_METAL_LIBRARY_NAME_10_14 = Metal_10_14_bbb
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) MY_METAL_LIBRARY_NAME_10_13='#"$(MY_METAL_LIBRARY_NAME_10_13)"' MY_METAL_LIBRARY_NAME_10_14='#"$(MY_METAL_LIBRARY_NAME_10_14)"'
Add xconfig as configuration (don't set it for project cause you will end up with double import)
Change PRODUCT_NAME variable of each metal library to a variable
Use preprocesor variables in code
static NSString *const kMetallibExtension = #"metallib";
NSString *const kMetalLibraryOldTarget = MY_METAL_LIBRARY_NAME_10_13; //#"Metal_10_13";
NSString *const kMetalLibraryFastMathTarget = MY_METAL_LIBRARY_NAME_10_14; //#"Metal_10_14";
+ (NSString *)metalLibraryName
{
if (#available(macOS 10.14, *)) {
return kMetalLibraryFastMathTarget;
} else {
return kMetalLibraryOldTarget;
}
//use default
//return #"default";
}

How do I get the iOS device CPU type? [duplicate]

Is there a way to identify the iOS device CPU architecture in runtime?
Thank you.
You can use sysctlbyname :
#include <sys/types.h>
#include <sys/sysctl.h>
#include <mach/machine.h>
NSString *getCPUType(void)
{
NSMutableString *cpu = [[NSMutableString alloc] init];
size_t size;
cpu_type_t type;
cpu_subtype_t subtype;
size = sizeof(type);
sysctlbyname("hw.cputype", &type, &size, NULL, 0);
size = sizeof(subtype);
sysctlbyname("hw.cpusubtype", &subtype, &size, NULL, 0);
// values for cputype and cpusubtype defined in mach/machine.h
if (type == CPU_TYPE_X86)
{
[cpu appendString:#"x86 "];
// check for subtype ...
} else if (type == CPU_TYPE_ARM)
{
[cpu appendString:#"ARM"];
switch(subtype)
{
case CPU_SUBTYPE_ARM_V7:
[cpu appendString:#"V7"];
break;
// ...
}
}
return [cpu autorelease];
}
I think this is the better way,
#import <mach-o/arch.h>
NXArchInfo *info = NXGetLocalArchInfo();
NSString *typeOfCpu = [NSString stringWithUTF8String:info->description];
//typeOfCpu = "arm64 v8"
Just adding more to #Emmanuel's answer:
- (NSString *)getCPUType {
NSMutableString *cpu = [[NSMutableString alloc] init];
size_t size;
cpu_type_t type;
cpu_subtype_t subtype;
size = sizeof(type);
sysctlbyname("hw.cputype", &type, &size, NULL, 0);
size = sizeof(subtype);
sysctlbyname("hw.cpusubtype", &subtype, &size, NULL, 0);
// values for cputype and cpusubtype defined in mach/machine.h
if (type == CPU_TYPE_X86_64) {
[cpu appendString:#"x86_64"];
} else if (type == CPU_TYPE_X86) {
[cpu appendString:#"x86"];
} else if (type == CPU_TYPE_ARM) {
[cpu appendString:#"ARM"];
switch(subtype)
{
case CPU_SUBTYPE_ARM_V6:
[cpu appendString:#"V6"];
break;
case CPU_SUBTYPE_ARM_V7:
[cpu appendString:#"V7"];
break;
case CPU_SUBTYPE_ARM_V8:
[cpu appendString:#"V8"];
break;
}
}
return cpu;
}
Here is the swift version of #Mahmut's answer.
import MachO
private func getArchitecture() -> NSString {
let info = NXGetLocalArchInfo()
return NSString(utf8String: (info?.pointee.description)!)!
}
print(getArchitecture() ?? "No architecture found")
Results
iPhone 12: ARM64E What is ARM64E?
Mac Mini M1
iOS 13 emulator: Intel 80486
iOS 14 emulator: ARM64E
MacBook Pro 16" x86_64 Intel:
iOS 13 emulator: `` (I don't have the emulators downloaded here)
iOS 14 emulator: Intel x86-64h Haswell
Feel free to update this.
I feel that this is the best answer for Swift yet:
import MachO
func getArch() -> String? {
guard let archRaw = NXGetLocalArchInfo().pointee.name else {
return nil
}
return String(cString: archRaw)
}
print("Current device architecture: \(getArch() ?? "Unknown Archetiture")")
For A11 (iPhone X, 8, 8+) and lower devices, the function above will return arm64, However for A12 (iPhone Xs, Xs Max, XR) and newer devices, it will return arm64e
Alternative answer that is Swift Package Manager compliant:
public func getMachineArchitecture() -> String {
#if arch(arm)
return "arm"
#elseif arch(arm64)
return "arm64"
#elseif arch(i386)
return "i386"
#elseif arch(powerpc64)
return "powerpc64"
#elseif arch(powerpc64le)
return "powerpc64le"
#elseif arch(s390x)
return "s390x"
#elseif arch(wasm32)
return "wasm32"
#elseif arch(x86_64)
return "x86_64"
#else
return "unknown_machine_architecture"
#endif
}

arduino programming: not enough memory message

I am new to arduino programming (Arduino Pro Mini 3.3v version), i have some code like below. I am connecting 9DOF, OLED screen and a BLE breakout to arduino pro mini.
I already went through some of the memory optimization tips, but i still have some issue. Even with the following code, i only have 9 bytes left for dynamic memory. If i enable BTLEserial.begin();, it will kill the memory. Please any suggestions will be appreciated.
#include <Wire.h>
#include <SPI.h>
#include <SparkFunLSM9DS1.h>
#include "Adafruit_BLE_UART.h"
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);
LSM9DS1 imu;
#define LSM9DS1_M 0x1E // Would be 0x1C if SDO_M is LOW
#define LSM9DS1_AG 0x6B // Would be 0x6A if SDO_AG is LOW
#define ADAFRUITBLE_REQ 10
#define ADAFRUITBLE_RDY 2
#define ADAFRUITBLE_RST 9
Adafruit_BLE_UART BTLEserial = Adafruit_BLE_UART(ADAFRUITBLE_REQ, ADAFRUITBLE_RDY, ADAFRUITBLE_RST);
void setup(void) {
Serial.begin(9600);
display.begin(SSD1306_SWITCHCAPVCC, 0x3D); // initialize with the I2C addr 0x3D (for the 128x64)
display.display();
delay(2000);
display.clearDisplay();
display.drawPixel(10, 10, WHITE);
display.display();
delay(2000);
display.clearDisplay();
imu.settings.device.commInterface = IMU_MODE_I2C;
imu.settings.device.mAddress = LSM9DS1_M;
imu.settings.device.agAddress = LSM9DS1_AG;
if (!imu.begin())
{
while (1)
;
}
// BTLEserial.begin(); - if i uncomment this code, i will get a not enough memory error.
}
aci_evt_opcode_t laststatus = ACI_EVT_DISCONNECTED;
void loop() {
displayAllDOF();
}
void displayAllDOF(){
display.setTextSize(1);
display.setTextColor(WHITE);
imu.readGyro();
display.setCursor(0,0);
display.print("G:");
display.print(imu.calcGyro(imu.gx));
display.print(", ");
display.print(imu.calcGyro(imu.gy));
display.print(", ");
display.print(imu.calcGyro(imu.gz));
display.println(" ");
imu.readAccel();
display.print("A:");
display.print(imu.calcAccel(imu.ax));
display.print(", ");
display.print(imu.calcAccel(imu.ay));
display.print(", ");
display.print(imu.calcAccel(imu.az));
display.println(" ");
imu.readMag();
display.print("M:");
display.print(imu.calcMag(imu.mx));
display.print(", ");
display.print(imu.calcMag(imu.my));
display.print(", ");
display.print(imu.calcMag(imu.mz));
display.println(" ");
display.display();
display.clearDisplay();
}
To start, you'll need to figure out where your RAM is going - How much does each library take? Do you really need to run them all at the same time? You know that you can run the display library, and the IMU code in your current setup - Can you implement something that only enables the IMU code, pulls data, then disables it? And the same with the display and BTLE code? That way each library is only consuming RAM when it's needed, and frees it once it's operation is finished
Update 1
An example of what I mentioned above. I do not know if all the libraries implement the .end() function. They may have a similar method you can use.
// Simple data storage for the .gx and .gy values
typedef struct {
float x, y;
} GyroData_t;
GyroData_t getImuData() {
GyroData_t data;
// Create the IMU class, gather data from it, and then destroy it
LSM9DS1 *imu = new LSM9DS1();
imu->begin();
imu->readGyro();
data.x = imu.gx;
data.y = imu.gy;
imu->end();
// This will reclaim the RAM that was used by the IMU - We no longer need it
delete imu;
return data;
}
void displayAllDOF() {
// Gather the IMU data
GyroData_t data = getImuData();
// Create the display object, and print the data we received
Adafruit_SSD1306 *display = new Adafruit_SSD1306(OLED_RESET);
display->print(...);
....
display->end();
// Reclaim the display RAM used
delete display;
// Do any bluetooth operations now
doBluetoothStuff();
}
void doBluetoothStuff() {
Adafruit_BLE_UART *BTLEserial = new Adafruit_BLE_UART(ADAFRUITBLE_REQ, ADAFRUITBLE_RDY, ADAFRUITBLE_RST);
BTLESerial->begin();
...
BTLESerial->end();
delete BTLESerial;
}

Detect if Swift app is being run from Xcode

I would like to programmatically determine if the iOS app is being run directly from XCode (either in the simulator or on a tethered device).
I've tried the -D DEBUG solution described here, but when I then disconnect from Xcode and re-run the app, it still thinks it's in debug mode.
I think what I'm looking for is a Swift version of this function
#include <assert.h>
#include <stdbool.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/sysctl.h>
static bool AmIBeingDebugged(void)
// Returns true if the current process is being debugged (either
// running under the debugger or has a debugger attached post facto).
{
int junk;
int mib[4];
struct kinfo_proc info;
size_t size;
// Initialize the flags so that, if sysctl fails for some bizarre
// reason, we get a predictable result.
info.kp_proc.p_flag = 0;
// Initialize mib, which tells sysctl the info we want, in this case
// we're looking for information about a specific process ID.
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PID;
mib[3] = getpid();
// Call sysctl.
size = sizeof(info);
junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
assert(junk == 0);
// We're being debugged if the P_TRACED flag is set.
return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
}
Clarification: Your C code (and the Swift version below) checks if
the program is run under debugger control, not if it's being run from
Xcode. One can debug a program outside of Xcode (by calling lldb or
gdb directly) and one can run a program from Xcode without debugging it
(if the “Debug Executable” checkbox in the scheme setting is off).
You could simply keep the C function and call it from Swift.
The recipes given in How do I call Objective-C code from Swift? apply to pure C code as well.
But it is actually not too complicated to translate that code to Swift:
func amIBeingDebugged() -> Bool {
// Buffer for "sysctl(...)" call's result.
var info = kinfo_proc()
// Counts buffer's size in bytes (like C/C++'s `sizeof`).
var size = MemoryLayout.stride(ofValue: info)
// Tells we want info about own process.
var mib : [Int32] = [CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()]
// Call the API (and assert success).
let junk = sysctl(&mib, UInt32(mib.count), &info, &size, nil, 0)
assert(junk == 0, "sysctl failed")
// Finally, checks if debugger's flag is present yet.
return (info.kp_proc.p_flag & P_TRACED) != 0
}
Update for Swift 5 (Xcode 10.7):
strideofValue and the related functions do not exist anymore,
they have been replaced by MemoryLayout.stride(ofValue:).
Remarks:
kinfo_proc() creates a fully initialized structure with all
fields set to zero, therefore setting info.kp_proc.p_flag = 0 is not necessary.
The C int type is Int32 is Swift.
sizeof(info) from the C code has to be strideOfValue(info)
in Swift to include the structure padding. With sizeofValue(info)
the above code always returned false in the Simulator for 64-bit devices. This was the most difficult part to figure out.
Swift 2 logic:
func amIBeingDebugged() -> Bool {
var info = kinfo_proc()
var mib : [Int32] = [CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()]
var size = strideofValue(info)
let junk = sysctl(&mib, UInt32(mib.count), &info, &size, nil, 0)
assert(junk == 0, "sysctl failed")
return (info.kp_proc.p_flag & P_TRACED) != 0
}
For those looking for a simpler solution - this works perfectly:
func isDebuggerAttached() -> Bool {
return getppid() != 1
}

What is the simplest way to retrieve the device serial number of an iOS device using MonoTouch?

Does MonoTouch have a simple mechanism for retrieving the device serial number (not UDID) of an iOS device? Is there a third-party library which I can use to obtain this?
In case it matters, I'm looking to use this functionality in an in-house application and am not concerned with the App Store approval process.
UPDATE: from iOS 8, we cannot retrieve the serial number of our iDevice.
To retrieve iphone serial number from Monotouch, you can use this technic:
Create a static library .a from XCode that have a function to get serial number
In MonoDevelop, create a binding project to bind you .a library into C# classes/functions (http://docs.xamarin.com/guides/ios/advanced_topics/binding_objective-c_libraries)
In your application, you call this binding library (in step 2).
For detail:
STEP 1. In my library.a, I have a class DeviceInfo, here is the implementation to get Serial number
#import "DeviceInfo.h"
#import <dlfcn.h>
#import <mach/port.h>
#import <mach/kern_return.h>
#implementation DeviceInfo
- (NSString *) serialNumber
{
NSString *serialNumber = nil;
void *IOKit = dlopen("/System/Library/Frameworks/IOKit.framework/IOKit", RTLD_NOW);
if (IOKit)
{
mach_port_t *kIOMasterPortDefault = dlsym(IOKit, "kIOMasterPortDefault");
CFMutableDictionaryRef (*IOServiceMatching)(const char *name) = dlsym(IOKit, "IOServiceMatching");
mach_port_t (*IOServiceGetMatchingService)(mach_port_t masterPort, CFDictionaryRef matching) = dlsym(IOKit, "IOServiceGetMatchingService");
CFTypeRef (*IORegistryEntryCreateCFProperty)(mach_port_t entry, CFStringRef key, CFAllocatorRef allocator, uint32_t options) = dlsym(IOKit, "IORegistryEntryCreateCFProperty");
kern_return_t (*IOObjectRelease)(mach_port_t object) = dlsym(IOKit, "IOObjectRelease");
if (kIOMasterPortDefault && IOServiceGetMatchingService && IORegistryEntryCreateCFProperty && IOObjectRelease)
{
mach_port_t platformExpertDevice = IOServiceGetMatchingService(*kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"));
if (platformExpertDevice)
{
CFTypeRef platformSerialNumber = IORegistryEntryCreateCFProperty(platformExpertDevice, CFSTR("IOPlatformSerialNumber"), kCFAllocatorDefault, 0);
if (CFGetTypeID(platformSerialNumber) == CFStringGetTypeID())
{
serialNumber = [NSString stringWithString:(__bridge NSString*)platformSerialNumber];
CFRelease(platformSerialNumber);
}
IOObjectRelease(platformExpertDevice);
}
}
dlclose(IOKit);
}
return serialNumber;
}
#end
STEP 2. In ApiDefinition.cs of my Binding Library project in Monotouch, I add this binding:
[BaseType (typeof (NSObject))]
public interface DeviceInfo {
[Export ("serialNumber")]
NSString GetSerialNumber ();
}
STEP 3. In my application, I import Reference to Binding library project in step 2, then add
using MyBindingProject;
...
string serialNumber = "";
try {
DeviceInfo nativeDeviceInfo = new DeviceInfo ();
NSString temp = nativeDeviceInfo.GetSerialNumber();
serialNumber = temp.ToString();
} catch (Exception ex) {
Console.WriteLine("Cannot get serial number {0} - {1}",ex.Message, ex.StackTrace);
}
Hope that helps. Don't hesitate if you have any question.

Resources