martes, 20 de septiembre de 2011

Eliminar Wine completamente

Hola a todos. Si quieres eliminar Wine completamente de tu sistema Linux, usando solo los comandos de desinstalación no es suficiente. Veremos entonces lo necesarios para purgar completamente Wine:

$ aptitude purge wine
$ rm -rf $HOME/.wine
$ rm -f $HOME/.config/menus/applications-merged/wine*
$ rm -rf $HOME/.local/share/applications/wine
$ rm -f $HOME/.local/share/desktop-directories/wine*
$ rm -f $HOME/.local/share/icons/????_*.xpm

domingo, 11 de septiembre de 2011

Crear librerías dinámicas en C++ para Windows usando CMake

Primero, la diferencia entre librería dinámica y librería estática:

Las librerías estáticas quedan incluidas en el ejecutable, mientras las dinámicas son ficheros externos, con lo que el tamaño de la aplicación (nuestro ejecutable) es mayor en el primer caso que en el segundo. Esto puede ser de capital importancia en aplicaciones muy grandes, ya que el ejecutable debe ser cargado en memoria de una sola vez

Las librerías dinámicas son ficheros independientes que pueden ser invocados desde cualquier ejecutable, de modo que su funcionalidad puede ser compartida por varios ejecutables. Esto significa que solo se necesita una copia de cada fichero de librería (DLL) en el Sistema. Esta característica constituye la razón principal de su utilización, y es también origen de algunos inconvenientes, principalmente en sistemas como Windows en los que existen centenares de ellas.

Referencia: Tipos de librerías en C y C++


Construcción de una DLL

Cuando se construye un fuente que será compilado para producir una DLL, los objetos (funciones y clases) que deban ser accesibles desde otros ejecutables, se denominan exportables, también callbacks si son funciones, en atención a una denominación muy usual en la literatura inglesa ("callback functions"). Esta circunstancia debe ser conocida por el compilador, por lo que es necesario especificar qué recursos se declaran "exportables"; además debe instruirse al "linker" para que genere una librería dinámica en vez de un ejecutable normal.

En los compiladores para la plataforma Windows existen varias formas para declarar una función o recurso como exportable, pero aquí veremos uno de los más simples y directos, el especificador dllexport.


Especificador dllexport
Los recursos "exportables" pueden ser también declarados mediante el especificador __declspec(dllexport).

Sintaxis:
Existen dos formas:
__declspec(dllexport) valor-devuelto funcion (argumentos);
class __declspec(dllexport) nombre-de-clase;
__declspec(dllexport) tipo-de-dato nombre-de-variable;


Ejemplos
extern "C" __declspec(dllexport) double MayorValor(double, double);
class __declspec(dllexport) A { /* ... */ };
__declspec(dllexport) int x;

Referencia: Crear una librería dinámica


Ahora sí, a la acción. Supongamos que tenemos tres archivos, así:


ArchivoDescripción
ClaseA.hppCabecera de la clase "ClaseA"
ClaseA.cppArchivo fuente con la definición de la clase "ClaseA"
main.cppCódigo del ejecutable


Donde la ClaseA estará contenida en la librería que queremos crear. Miremos el código de cada una de los archivos:


ClaseA.hpp

#ifndef CLASEA_HPP
#define CLASEA_HPP

class __declspec(dllexport) ClaseA
{
public:
ClaseA(int iId = 0);

int id() const;
void id(const int &iId);

protected:
int _iId;
};

__declspec(dllexport) ClaseA * nuevaReferencia(int iId = 0);
__declspec(dllexport) void eliminarReferencia(ClaseA * pClaseA);

// Definición de métodos inline
inline int ClaseA::id() const
{
return _iId;
}

inline void ClaseA::id(const int &iId)
{
_iId = iId;
}

#endif



ClaseA.cpp

#include<ClaseA.hpp>

ClaseA::ClaseA(int iId)
{
_iId = iId;
}

ClaseA * nuevaReferencia(int iId)
{
return new ClaseA(iId);
}

void eliminarReferencia(ClaseA * pClaseA)
{
delete pClaseA;
}


main.cpp

#include<iostream>
#include<ClaseA.hpp>

using std::cout;
using std::endl;

int main(int argc, char **argv)
{
cout << "Ejemplo de creación de librerías dinámicas" << endl;

ClaseA * pClaseA = nuevaReferencia();

cout << "id:\t" << pClaseA->id() << endl;

pClaseA->id(3);

cout << "id:\t" << pClaseA->id() << endl;

eliminarReferencia(pClaseA);

return 0;
}



Tenemos una clase llamada ClaseA que estará contenida en nuestra librería. Y un archivo main.cpp que contiene el código de nuestro ejecutable.

Ahora creamos el archivo de configuración de CMake:

CMakeLists.txt

project(libreria)
cmake_minimum_required(VERSION 2.8)

include_directories( ${CMAKE_BINARY_DIR} . )

add_library(Core SHARED
ClaseA.hpp
ClaseA.cpp
)

add_executable(main main.cpp)

target_link_libraries(main Core)



Creamos una librería dinamica (SHARED) llamada Core, y un ejecutable llamado main.

Miremos que no es necesario declarar como exportables los métodos y miembros de la clase, ya que la clase es exportable.

En el momento de construcción de la librería ciertos identificadores deben ser declarados dllexport. Pero para poder usar esta en la construcción de otras librerías o ejecutables es necesario importarlos. Para esto usamos el especificador dllimport. Para esto es necesario que en el momento de construcción el especificador dllexport sea cambiado por dllimport. Para automatizar esto, usaremos un cuarto archivo LibExport.hpp:

LibExport.hpp

#ifndef LIBEXPORT_HPP
#define LIBEXPORT_HPP

#ifdef _WIN32
# ifdef Core_EXPORTS
# define EXPORT __declspec( dllexport )
# else
# define EXPORT __declspec( dllimport )
# endif
#else
# define EXPORT
#endif

#endif




En el momento en que se está construyendo la librería, CMake define un macro llamado <nombre de la librería>_EXPORTS. Lo que hacemos es aprovechar esto y decir, que cuando se esté construyendo la librería, EXPORT adquiera el valor de __declspec( dllexport ), de lo contrario tendrá el valor de __declspec( dllimport ) (siempre y cuando el sistema operativo sea Windows). Luego de esto, modificamos ClaseA.hpp para que soporte tanto dllexport como dllimport:

ClaseA.hpp


#ifndef CLASEA_HPP
#define CLASEA_HPP

#include<libexport.hpp>


class EXPORT ClaseA
{
public:
ClaseA(int iId = 0);

int id() const;
void id(const int &iId);

protected:
int _iId;
};

EXPORT ClaseA * nuevaReferencia(int iId = 0);
EXPORT void eliminarReferencia(ClaseA * pClaseA);

// Definición de métodos inline
inline int ClaseA::id() const
{
return _iId;
}

inline void ClaseA::id(const int &iId)
{
_iId = iId;
}

#endif



Cuando compilamos el proyecto, podemos ver que se crean tres archivos; main.exe, Core.dll, Core.obj. Esta ultima una librería estática clásica que sirve como índice o diccionario de la dinámica.