Archivos de Categoría: Xcode

Solucionar “macports checking for Tcl configuration… configure: error: Can’t find Tcl configuration definitions” al actualizar Macports en Mac OS X 10.9 Mavericks

Solucionar "macports checking for Tcl configuration... configure: error: Can't find Tcl configuration definitions" al actualizar Macports en Mac OS X 10.9 Mavericks">

Acabo de actualizar mi Mac OS X a Mavericks 10.9. Al intentar actualizar Macports me daba un error, y al ejecutar el selfupdate en modo verboso (sudo port -v selfupdate) me salió esto:

macports checking for Tcl configuration... configure: error: Can't find Tcl configuration definitions

Solucioné el problema reinstalando las Command Line Tools de Xcode y aceptando la licencia desde la consola de comandos:

sudo xcode-select --install
sudo xcodebuild -license

Luego el selfupdate funcionó perfectamente:

sudo port selfupdate

No puedo configurar con cmake en Mac OS X 10.8 con Xcode 4.4

Acababa de hacer una instalación limpia de Mac OS X 10.8 Mountain Lion y Xcode 4.4 y cuando me disponía a compilar (otra vez) OpenCV 2.4.2 me apareció este error al hacer “cmake ..”:

$ cmake ..
CMake Error: CMake was unable to find a build program corresponding to "Unix Makefiles".  CMAKE_MAKE_PROGRAM is not set.  You probably need to select a different build tool.
CMake Error: Error required internal CMake variable not set, cmake may be not be built correctly.
Missing variable is:
CMAKE_CXX_COMPILER_ENV_VAR
CMake Error: Error required internal CMake variable not set, cmake may be not be built correctly.
Missing variable is:
CMAKE_CXX_COMPILER
CMake Error: Could not find cmake module file:/Users/enekochan/compilaciones/OpenCV-2.4.2/build/CMakeFiles/CMakeCXXCompiler.cmake
CMake Error: Error required internal CMake variable not set, cmake may be not be built correctly.
Missing variable is:
CMAKE_C_COMPILER_ENV_VAR
CMake Error: Error required internal CMake variable not set, cmake may be not be built correctly.
Missing variable is:
CMAKE_C_COMPILER
CMake Error: Could not find cmake module file:/Users/enekochan/compilaciones/OpenCV-2.4.2/build/CMakeFiles/CMakeCCompiler.cmake
CMake Error: CMAKE_CXX_COMPILER not set, after EnableLanguage
CMake Error: CMAKE_C_COMPILER not set, after EnableLanguage
-- Configuring incomplete, errors occurred!

Las nuevas versiones de Xcode (4.4 y siguientes) no se instalan en /Developer por lo que pensé que podía ser un problema de paths, pero lo que sucede en realidad es que ya no se instalan por defecto con Xcode las utilidades de terminal. Puedes instalarlas y aceptar la licencia desde el terminal:

sudo xcode-select --install
sudo xcodebuild -license

O bajártelas por separado de https://developer.apple.com/downloads/ (necesitas una Apple ID). Buscar ahí la última “Command Line Tools” para vuestro sistema:

Instalarlo y ya podréis compilar desde el terminal sin problemas.

Source: http://www.cmake.org/pipermail/cmake/2009-February/027317.html

Usar el Simulador de Xcode con un plug-in para iOS en Unity 3

Como ya se vio en “Crear una applicación Unity 3 con Plugin de código nativo para iOS” podemos crear un plug in the código nativo para iOS en Unity 3. El problema es que por defecto no se pueden probar las llamadas a código nativo en el Simulador de Xcode. Probablemente no tenga mucho sentido probar una aplicación Unity 3 en el simulador ya que el rendimiento 3D puede variar mucho con el del dispositivo real, pero si todavía no tienes un dispositivo iOS puede servirte.

Dentro del proyecto Xcode en el fichero “Libraries/RegisterMonoModules.cpp” se puede ver como las funciones definidas dentro del “extern” están dentro de un bloque que solo se procesa cuando el target NO ES el Simulator (#if !(TARGET_IPHONE_SIMULATOR)). Tenemos que sacar de esos bloques tanto la definición de la función que registra las funciones (mono_dl_register_symbol) como nuestras funciones propiamente dichas. Fijarse en las líneas marcadas en negrita a continuación:

#include "RegisterMonoModules.h"

extern bool gEnableGyroscope;

extern "C"
{
        typedef void* gpointer;
        typedef int gboolean;
#if !(TARGET_IPHONE_SIMULATOR)
        const char*                     UnityIPhoneRuntimeVersion = "3.5.0f5";

        extern int                      mono_ficall_flag;
        void                            mono_aot_register_module(gpointer *aot_info);
        extern gboolean         mono_aot_only;
        extern gpointer*        mono_aot_module_Assembly_CSharp_firstpass_info; // Assembly-CSharp-firstpass.dll
        extern gpointer*        mono_aot_module_UnityEngine_info; // UnityEngine.dll
        extern gpointer*        mono_aot_module_mscorlib_info; // mscorlib.dll
#endif // !(TARGET_IPHONE_SIMULATOR)
        void                         mono_dl_register_symbol (const char* name, void *addr);
        void    _PassStructFromObjCToUnity();
        void    _Test();
}
void RegisterMonoModules()
{
    gEnableGyroscope = false;
#if !(TARGET_IPHONE_SIMULATOR)
        mono_aot_only = true;
        mono_ficall_flag = false;
        mono_aot_register_module(mono_aot_module_Assembly_CSharp_firstpass_info);
        mono_aot_register_module(mono_aot_module_UnityEngine_info);
        mono_aot_register_module(mono_aot_module_mscorlib_info);


#endif // !(TARGET_IPHONE_SIMULATOR)
        mono_dl_register_symbol("_PassStructFromObjCToUnity", (void*)&_PassStructFromObjCToUnity);
        mono_dl_register_symbol("_HaveObjCDoSomething", (void*)&_HaveObjCDoSomething);
}

Podemos modificar el scriptPostprocessBuildPlayer” para no tener que hacer estos cambios a mano cada vez que generemos el proyecto Xcode. Un poco de awk hace la magia (no es muy bonito el código pero funciona…):

#!/bin/bash
cp -fR ./iOS\ Build/Libraries ~/Documents/Xcode/my-project/
cp -fR ./iOS\ Build/Data ~/Documents/Xcode/my-project/
rm file.tmp
awk '
{
  if ($0 == "#if !(TARGET_IPHONE_SIMULATOR)" && NR == 9) {
    getline var1;
    getline var2;
    printf "%s\n%s\n%s\n", var2, $0, var1 >> "file.tmp"
  } else if (NR == 32) {
     printf "#endif // !(TARGET_IPHONE_SIMULATOR)" >> "file.tmp"
     printf "\n%s\n", $0 >> "file.tmp"
  } else if ($0 == "#endif // !(TARGET_IPHONE_SIMULATOR)" && NR > 32) {
  } else {
    print $0 >> "file.tmp"
  }
}' ~/Documents/Xcode/my-project/Libraries/RegisterMonoModules.cpp
mv file.tmp ~/Documents/Xcode/my-project/Libraries/RegisterMonoModules.cpp

Probablemente sea una buena idea desactivar la opción “Dead Code Stripping” del proyecto Xcode (dentro de “Linking” en “Build Settings”) ya que Xcode puede pensar que las funciones definidas como externas no serán nunca llamadas desde Xcode ya que son llamadas desde Unity.

Fuente: http://answers.unity3d.com/questions/49945/gamekit-linker-failure.html?sort=oldest

Crear una aplicación Unity 3 con Plugin de código nativo para iOS

Crear un nuevo proyecto en Unity3D. Ir a “File->Build Settings”, seleccionar la plataforma iOS y luego “Player Settings…”. En “Other Settings” dentro de “Identification” configurar el “Bundle Identifier” por ejemplo con “com.YourCompanyName.YourProductName”

Si no se hace esto dará este error al hacer el “Build”.

NOTA: Si se va a ejecutar en el simulador de Xcode hay que configurar la opción “SDK Version” a una versión de simulador (“iOS Simulator Latest” por ejemplo o la versión de iOS deseada), ya que en caso contrario (si se elige una para dispositivo como por ejemplo “iOS Latest” u otra versión concreta) aparecerán errores acerca de que no están definidas cientos de funciones para la arquitectura i386 al compilar el proyecto de Xcode. Si este paso se hace mal habrá que volver a hacer “Build” en Unity y volver a copiar las carpetas “Libraries” y “Data” a nuestro proyecto Xcode como se va a explicar a continuación.

Una vez configurados el “Bundle Identifier” y la “SDK Version” salvar la escena y el proyecto donde se quiera. Al ejecutar “Build And Run” y se creará un nuevo proyecto de Xcode (llamado “Unity-iPhone”) dentro de la carpeta de nuestro proyecto de Unity con el nombre que nosotros queramos, por ejemplo “iOS Build”. Hay que copiar TODA esa carpeta a otra parte, por ejemplo donde residen tus proyectos de Xcode.

Cuando hagamos algún cambio en nuestro proyecto de Unity y hagamos otra vez “Build” nos pedirá donde guardar el proyecto de Xcode que genera, pero podemos sobreescribir el original (el que se crea dentro de la carpeta de nuestro proyecto Unity) sin problemas. Lo que si habrá que hacer es copiar TODOS los ficheros de las carpetas “Data” y “Libraries” del proyecto Xcode que ha vuelto a crear Unity cuando hace el “Build” a las correspondientes en el proyecto de Xcode que hemos copiado nosotros la primera vez. Se puede usar un script similar a este y ejecutarlo a mano después de hacer “Build”:

#!/bin/bash
cp -Rf ./iOS\ Build/Data ~/Documents/Xcode/my-project/
cp -Rf ./iOS\ Build/Libraries ~/Documents/Xcode/my-project/

De todas maneras la mejor opción para conseguir el mismo efecto es crear un script PostprocessBuildPlayer (ojo que el fichero tenga permisos de ejecución) dentro de “Assets/Editor” (por lo que habrá que crear una carpeta llamada Editor dentro de la vista de “Project” y copiar ahí es script) con el mismo contenido que el anterior para que los ficheros se copien automaticamente a nuestro proyecto de Xcode cada vez que hagamos “Build” en Unity. Los scripts PostprocessBuildPlayer pueden ser shell script o Perl script.

Abrir nuestro proyecto de Xcode y cambiar el nombre del fichero “iPhone_target2AppDelegate.m” (puede tener un nombre diferente según la versión de Unity pero la cuestión es hacerlo en el fichero “AppDelegate”, por tanto será cuestión de ver qué fichero tiene al final puesto precisamente “AppDelegate”) a “iPhone_target2AppDelegate.mm” (es decir 2 emes al final en vez de solo 1). Esto sirve para que Xcode lo compile como código Objetive-C++.

En ese fichero justo encima de “ ...” poner lo siguiente:

static iPhone_target2AppDelegate *delegateObject;

Dentro del método “applicationDidFinishLaunching” añadir la siguiente línea que aparece en negrita como primera instrución a ejecutar:

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    delegateObject = self;
    ...
}

Al final del “AppDelegate” (es decir el fichero “iPhone_target2AppDelegate.mm”), pero antes de la claúsula , poner el siguiente código que crea 2 métodos que pueden ser llamados desde el exterior. Uno de ellos acepta como parámetro una estructura por referencia a la que se modifican sus valores (los métodos usados para obtener el nuevo valor no están creados ya que solo es un ejemplo) y el otro que sin más ejecuta un método del “AppDelegate” que nosotros debemos crear.

NSString* CreateNSString (const char* string) {
    return [NSString stringWithUTF8String: string ? string : ""];
}

char* MakeStringCopy (const char* string) {
    if (string == NULL) return NULL;
    char* res = (char*)malloc(strlen(string) + 1);
    strcpy(res, string);
    return res;
}

struct MyStruct {
    char* stringValue;
    int intValue;
};

extern "C" {    
    void _PassStructFromObjCToUnity ( struct MyStruct *myStruct ) {
        NSLog(@"_PassStructFromObjCToUnity");

        myStruct->stringValue = MakeStringCopy([delegateObject.someStringProperty UTF8String]);
        myStruct->intValue = [delegateObject.someNSNumberProperty intValue];

        printf("-> myStruct->stringValue %s\n", myStruct->stringValue);
        printf("-> myStruct->intValue %i\n", myStruct->intValue);
        NSLog(@"-> complete.");
    }

    void _HaveObjCDoSomething () {
        NSLog(@"_HaveObjCDoSomething");
        [delegateObject doSomething];
        NSLog(@"-> complete.");
    }   
}

Ahora volvemos a nuestro proyecto de Unity y dentro de una clase C# en Assets/Plugins/ podríamos poner algo similar a esto, que sería quien se encargaría de llamar a nuestros métodos definidos dentro de “extern "C"”.

using UnityEngine;
using System.Runtime.InteropServices;

public struct MyStruct
{
    public string stringValue;
    public int intValue;
}

public class OBJCPlugin 
{
    [DllImport ("__Internal")]
    private static extern void _PassStructFromObjCToUnity ( ref MyStruct myStruct );

    public static MyStruct PassStructFromObjCToUnity ()
    {
        Debug.Log("OBJCPlugin.PassStructFromObjCToUnity");
        MyStruct data = new MyStruct();
        if ( Application.platform == RuntimePlatform.IPhonePlayer )
        {
                _PassStructFromObjCToUnity( ref data );
        }
        return data;
    }   

    [DllImport ("__Internal")]
    private static extern void _HaveObjCDoSomething ();

    public static void HaveObjCDoSomething ()
    {
        Debug.Log("OBJCPlugin.HaveObjCDoSomething");
        if ( Application.platform == RuntimePlatform.IPhonePlayer )
        {
                _HaveObjCDoSomething();
        }
    }
}

Como hemos modificado el proyecto de Unity para que llame a las funciones en código nativo de iOS hay que volver a hacer el “Build” y copiar las carpetas “Libraries” y “Data” a nuestro proyecto Xcode (aunque si hemos creado el script PostprocessBuildPlayer las carpetas se copian automáticamente. De esta manera ya se juntan tanto las llamadas hechas desde C# en Unity como el código nativo escrito en nuestro proyecto Xcode.

Si quieres poder ejecutar este proyecto Xcode en el simulador lee el post “Usar el Simulador de Xcode con un plug-in para iOS en Unity 3“.

Fuentes: http://answers.unity3d.com/questions/10110/specific-steps-to-set-up-a-plugin-for-iphone-in-xc.html
http://www.tinytimgames.com/2010/01/10/the-unityobjective-c-divide/

Usar OpenCV en Xcode 4 para una aplicación orientada a objetos Mac OS X

Lo primero de todo es instalar OpenCV en Mac OS X. Luego en Xcode 4 crear un nuevo proyecto de aplicación para Mac OS X de tipo “Command Line Tool”.

Poner un nombre de proyecto en “Product Name” y en “Type” elegir “Foundation”.

En la pestaña “Build Settings” (haciendo click en el icono azul del proyecto a la izquierda) añadir a las siguientes opciones estos valores:

Dentro de “Search Paths”:
Header Search Paths: /usr/local/include
Library Search Paths: /usr/local/lib
Dentro de “Linking”:
Other Linker Flags: -lopencv_core -lopencv_highgui -lopencv_imgproc

NOTA: Se pueden añadir más librerías en “Other Linker Flags” para incluir más funciones de OpenCV como por ejemplo:

-lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_legacy -lopencv_contrib -lopencv_calib3d -lopencv_features2d -lopencv_flann -lopencv_ml -lopencv_objdetect -lopencv_video

Si quieres usar también las funciones en C de OpenCV tienes que cambiar dentro de “Build Options” el siguiente parámetro:

Compiler for C/C++/Objetive-C: LLVM GCC 4.2

Cambiar el nombre del fichero “main.m” a “main.mm“. Esto hace que el código se intérprete como Objetive-C++ en vez de solo como Objetive-C.

Ahora (MUY IMPORTANTE) dentro del fichero .pch de la carpeta de proyecto “Supporting Files” añadir ANTES de cualquier otro import el siguiente import:

#ifdef __cplusplus
    #import "opencv2/opencv.hpp"
#endif

Esto se debe a que OpenCV tiene definida una macro MIN que también existe en el framework de Apple y si no se pone la de OpenCV antes aparecen errores del tipo “LLVM GCC 4.2 Error: Statement-expressions are allowed only inside functions” o “opencv2/core/core.hpp:433: error: statement-expressions are allowed only inside functions“. El import está rodeado de ese “ifdef” para que los ficheros que no usan código Objetive-C++ puedan mantener la extensión “.m” y no haga falta modificar todos a “.mm“.

Rellenar el fichero “main.mm” con el siguiente código de ejemplo, que es de hecho la versión Orientada a Objetos del ejemplo que usé en Usar OpenCV en Xcode 4 para una aplicación Mac OS X:

//
// main.mm
// OpenCVOOTest
//
// Created by __MyName__ on 16/09/11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import 
#import "opencv2/opencv.hpp"

using namespace cv;

int main (int argc, const char * argv[])
{
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    
    Mat img(cv::Size(640, 480), CV_8UC3);
    
    circle(img, cv::Point(320, 240), 100, Scalar(255, 0, 0, 255), 5, 8, 0);
    
    namedWindow("OpenCV Window", CV_WINDOW_NORMAL);

    imshow("OpenCV Window", img);
    
    waitKey(0);
    
    [pool drain];
    return 0;
}

Si al hacer el linkado de la aplicación da el siguiente error:

"Undefined symbols for architecture x86_64:"

Seguido de un montón de nombres de funciones, hay que cambiar la arquitectura del programa a i386. Para ello dentro del “Build Settings” del proyecto cambiar la opción “Arquitectures” a “32-bit Intel”. Esto por sí solo tal vez no resuelva el problema, ya que OpenCV tiene que estar también compilado para i386 32 bits.

Fuentes: http://stackoverflow.com/questions/3810800/how-to-include-opencv-in-cocoa-application
http://computer-vision-talks.com/2011/03/opencv-build-script-with-xcode-4-support-is-here

  • Page 1 of 2
  • 1
  • 2
  • >