# Programmation

Quelle est la valeur par défaut de max-old-space-size dans NodeJS ?

Posté le 14. June 2024 dans ProgrammationTags: javascript, nodejs

Temps de lecture: 5 min

Bonjour à tous,

Lors de nos développements en NodeJS, il arrive parfois que l'on se retrouve confronté à des erreurs. Certaines de ces erreurs ne se reproduisent pas en local, mais uniquement sur un environnement distant. C'est ce qui nous est arrivé récemment lors de l'exécution de la commande npm ci sur la chaîne de déploiement continue.

L'erreur que nous avons rencontrée est la suivante :

<--- Last few GCs --->

[14040:0x56930a0]    96150 ms: Mark-Compact 2012.5 (2093.0) -> 2011.8 (2092.0) MB, 902.72 / 17.13 ms  (average mu = 0.416, current mu = 0.217) allocation failure; scavenge might not succeed
[14040:0x56930a0]    97002 ms: Mark-Compact 2019.6 (2092.0) -> 2019.1 (2112.8) MB, 843.10 / 0.00 ms  (average mu = 0.251, current mu = 0.011) allocation failure; scavenge might not succeed

<--- JS stacktrace --->

FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory

Cette erreur se produit lorsque la mémoire allouée pour NodeJS est insuffisante (le garbage collector de NodeJS n'arrive pas à nettoyer la mémoire). Pour résoudre ce problème, l'une des possibilités est d'augmenter la mémoire allouée à NodeJS. ...


Lire la suite ...

Woodstock Backup - Reverse engineering de BackupPC

Posté le 7. May 2024 dans ProgrammationTags: woodstock, backup, sauvegarde, javascript, nodejs

Temps de lecture: 21 min

Une partie de cet article a été publiée sur LinuxFR. Après avoir reçu quelques retours, j'ai décidé de publier une version modifiée et améliorée de cet article sur mon blog.

Je remercie donc la communauté de LinuxFR pour ses retours. :D

Les commentaires sur le code ou sur l'article sont les bienvenus.

...


Lire la suite ...

Woodstock Backup - Optimiser la consommation mémoire de Node.js avec Rust

Posté le 10. May 2023 dans ProgrammationTags: woodstock, backup, sauvegarde, javascript, nodejs

Temps de lecture: 15 min

Introduction

Node.js est un environnement d'exécution JavaScript côté serveur qui repose sur le moteur JavaScript V8 de Google. Il est utilisé pour développer des applications serveur en back-end d'une application web, des outils en ligne de commande et des applications desktop. Cependant, la consommation de mémoire peut être un problème pour certaines applications Node.js, en particulier celles qui manipulent de grandes quantités de données ou des données volumineuses.

Dans cet article, nous allons voir comment optimiser la consommation de mémoire d'une application Node.js en le couplant avec Rust. Rust est un langage de programmation système qui offre des performances similaires à celles du C++, tout en offrant une sécurité de mémoire à la compilation. Rust peut être utilisé pour écrire des bibliothèques C/C++ natives pour Node.js.

Problématique

J'ai développé un logiciel de sauvegarde appelé Woodstock Backup, écrit en TypeScript. Lors du lancement des sauvegardes, il crée une représentation du système de fichier en mémoire et nécessite une grande quantité de mémoire. Pour illustrer cela, nous avons reproduit notre cas avec le code suivant :

const filesize = require("filesize.js");
const fs = require("fs");
// Utilisation des méthodes de sérialisation et de désérialisation du moteur V8
const { serialize, deserialize } = require("v8");

// Méthode pour générer une chaîne de caractère contenant des caractères aléatoires
function randomString(size) {
  const buffer = Buffer.alloc(size);
  for (let i = 0; i < size; i++) {
    buffer[i] = Math.floor(Math.random() * 256);
  }
  return buffer;
}

// Méthode pour générer un nombre aléatoire de la taille d'un nombre de 53 bits
function randomNumber() {
  return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
}

// Création d'un objet de test en javascript contenant que des données aléatoires
const testObject = () => ({
  path: randomString(100),
  stats: {
    ownerId: { low: randomNumber(), high: randomNumber(), unsigned: true },
    groupId: { low: randomNumber(), high: randomNumber(), unsigned: true },
    size: { low: randomNumber(), high: randomNumber(), unsigned: true },
    compressedSize: {
      low: randomNumber(),
      high: randomNumber(),
      unsigned: true,
    },
    lastRead: { low: randomNumber(), high: randomNumber(), unsigned: true },
    lastModified: { low: randomNumber(), high: randomNumber(), unsigned: true },
    created: { low: randomNumber(), high: randomNumber(), unsigned: true },
    mode: { low: randomNumber(), high: randomNumber(), unsigned: true },
    dev: { low: randomNumber(), high: randomNumber(), unsigned: true },
    rdev: { low: randomNumber(), high: randomNumber(), unsigned: true },
    ino: { low: randomNumber(), high: randomNumber(), unsigned: true },
    nlink: { low: randomNumber(), high: randomNumber(), unsigned: true },
  },
  chunks: [randomString(32), randomString(32), randomString(32)],
  sha256: randomString(32),
});

// Lancement du GC pour s'assurer que la mémoire utilisé ne contient que les objets de test
global.gc();
// On recupère la mémoire utilisé avant le test
const memoryBefore = process.memoryUsage().heapUsed;
// On recupère le temps avant le test (pour mesurer le temps de traitement)
const time = Date.now();

// Création des objets. J'ai du lancer plusieurs fois le script pour trouver une valeur qui ne causé pas de crash de 
// Node.JS pour cause de manque de mémoire
const nbObjects = 1_300_000;
const testArray = new Array(nbObjects);
for (let i = 0; i < nbObjects; i++) {
  testArray[i] = testObject();
}

// Combien de temps à pris la création des objets
console.log("Creation time: ", Date.now() - time);
// Lancement du GC pour s'assurer que nous n'avons pas d'autres reliquats
global.gc();
// Récupération de la mémoire après le test
const memoryAfter = process.memoryUsage().heapUsed;

console.log("Memory consumption: ", filesize.default(memoryAfter - memoryBefore));
console.log("Memory consumption by objects: ", filesize.default((memoryAfter - memoryBefore) / nbObjects));

// Dans la suite on va écrire un fichier contenant le contenu de la mémoire. Cela a été fait initiallement pour 
// s'assurer que le GC ne supprime pas mes objets car non utilisés.
const time2 = Date.now();

// Remove test file if exist
try {
  fs.unlinkSync("test");
} catch (e) {}

const stream = fs.createWriteStream("test");

// C'est moche, mais c'est pour tester
stream.on("close", () => {
  console.log("Write to file time: ", Date.now() - time2);
  // Size of file test on disk
  const stats = fs.statSync("test");
  console.log("Size of file on disk: ", filesize.default(stats.size));
  console.log(
    "Size of object in the file",
    filesize.default(stats.size / nbObjects)
  );
});

for (const obj of testArray) {
  stream.write(serialize(obj));
}
stream.end();

En estimant rapidement la mémoire que la taille de l'objet aurait dû prendre, je l'estime à environ 432 octets (12 nombres de 2*64 bits + 1 octet de boolean + 128 caractères pour les chunks et 100 caractères pour le nom). ...


Lire la suite ...

Woodstock Backup - Protocol et Language de sauvegarde

Posté le 7. April 2023 dans ProgrammationTags: woodstock, backup, sauvegarde, javascript, nodejs

Temps de lecture: 18 min

Woodstock Backup - Protocol et Language de sauvegarde

Note de 2023 : Ce billet a été écrit en avril 2021, il y a deux ans, mais n'a jamais été publié. Le temps passe vite.

Depuis lors, j'ai travaillé sur d'autres projets, mais aussi sur ce logiciel de sauvegarde. En progressant dans le développement du projet, j'ai pu optimiser les performances et me faire une opinion sur le choix que j'ai finalement fait, que je partagerai à la fin de l'article.

Je mettrai à jour mes conclusions en fonction de mes avancées sur le sujet.

...

Lire la suite ...

Du souhait d'achat d'un vélo ...

Posté le 27. September 2021 dans ProgrammationTags: javascript, nodejs, aws, web, velo, sms

Temps de lecture: 17 min

Que penseriez-vous si je vous racontais un peu mes vacances ? Attendez ... attendez ... ne partez pas ... l'histoire est intéressante, et surtout nous allons parler informatique.

Début Août j'ai décidé de m'acheter un nouveau vélo (un VTC à assistance électrique). Le choix du vélo importe peu, mais du fait d'une pénurie de matière première et d'une forte demande en vélo depuis le début de la crise de mes sanitaire, tous les vélos sont en rupture de stock.

J'ai fait le choix personnel de me rendre dans une enseigne connue dont le nom est aussi une discipline de l'athlétisme pour acheter ce VTC.1

Et là c'est le drame. ...


Lire la suite ...

Comment créer une bonne API Web - Partie 3

Posté le 29. November 2020 dans ProgrammationTags: api, graphql, rest, javascript, nodejs

Temps de lecture: 18 min

Bonjour,

Cet article fait partie d'un ensemble:

Il y a quelques années de cela, j'ai souhaité résoudre un problème que j'ai depuis longtemps avec les API REST: comment bien normaliser les tris, les projections, et les filtres. En effectuant mes recherches je suis tombé sur deux frameworks qui permettent de résoudre le problème des projections.

Qu'est qu'une API Falcor

Je ne vais parler que succinctement de Falcor. C'est un framework que je n'ai pas utilisé mais j'ai tout de même été très intéressé par ce dernier et je vais écrire quelques lignes sur ce Framework. ...


Lire la suite ...

L'Application du confinement pour se déplacer

Posté le 14. November 2020 dans ProgrammationTags: android, programmation, java, confinement

Temps de lecture: 10 min

Préambule: A cause du temps de validation du PlayStore, je publie cet article avec une semaine de retard.

Cela fait plus d'une semaine (quand j'écris ces lignes) que le re-confinement à commencé. Quand je vais courir, je dois me cantonner à 1km autour de chez moi. Mais quand je cours j'aimerais que mon téléphone intelligent me prévienne quand j'approche du rayon de 1km ou quand je le dépasse. Je ne souhaite pas avoir le nez sur une carte de mon téléphone.

Je regarde ce qui se fait. J'ai trouvé l'application suivante sur le play store : 1km. L'application m'avait l'air de répondre à mes critères mais ne fonctionnait pas lors de mon utilisation (en plus il y avait de la pub).

Une autre application 1km pourrait répondre à mon besoin mais je ne l'ai pas testé. ...


Lire la suite ...

Comment créer une bonne API Web - Partie 2

Posté le 2. November 2020 dans ProgrammationTags: api, graphql, rest, javascript, nodejs

Temps de lecture: 16 min

Bonjour,

Cet article fait partie d'un ensemble:

Qu'est qu'une API REST

REST est une norme dont voici les grandes lignes. Il n'est pas dans mon but de faire un cours sur REST (et il y en déjà de très bons sur internet). Je souhaiterais surtout parler des points qui me semblent importants. N'hésitez pas à venir me dire si vous pensez qu'il manque des points importants. Je viendrai alors compléter mon article.

Le principe de REST est de séparer l'API en différentes ressources logiques qui peuvent être manipulées par les verbes HTTP (GET, POST, ...). La réponse de son côté se base également sur les codes http. ...


Lire la suite ...

Comment créer une bonne API Web - Partie 1

Posté le 11. October 2020 dans ProgrammationTags: api, graphql, rest, javascript, nodejs

Temps de lecture: 10 min

Bonjour,

Je souhaite vous parler de l'écriture d'API. Je vais découper cet article en 3 parties:

Je me limiterai au WEB et aux normes REST et GraphQL même s'il y a d'autres normes/frameworks pour écrire des API.

Commençons donc par le début ! Qu'est-ce qu'une API ? API signifie Application Programming Interface. C'est une interface de programmation prête à être consommée par un client. ...


Lire la suite ...

FindSimilarity - Trouver les différences entre plusieurs vidéos

Posté le 10. December 2016 dans ProgrammationTags: qt, opencv, video, debian

Temps de lecture: 12 min

Introduction

Bonjour,

Je souhaite vous présenter une petite expérience que je viens d'écrire.

Cela fait plusieurs années que je souhaitais m'amuser sur la librairie OpenCV mais sans jamais en avoir eu l'utilité. J'ai profité d'avoir un peu de temps libre, pour écrire un petit programme dont le but est de comparer un ensemble de vidéos.

Le but est ensuite de dire si dans cet ensemble de vidéos, deux vidéos sont identiques, ou se ressemblent, ou sont trop éloignées. ...


Lire la suite ...

Cross-Compilation - Compiler un programme pour MS/Windows sous Gnu/Linux

Posté le 1. July 2012 dans ProgrammationTags: qt

Temps de lecture: 7 min

Qu'est que la cross-compilation1 ?

La cross compilation est la possibilité sur une machine avec un matériel spécifique (architecture) et avec un système d'exploitation donné, de compiler des programmes pour une autre architecture, ou pour un autre système d'exploitation.

Cela peut être utilisé par exemple pour compiler un programme sur votre ordinateur de tous les jours (sous Gnu/Linux, avec une architecture i386) à destination de votre téléphone mobile, qui lui est sous Symbian avec un processeur ARM.

Les raisons de faire de la compilation croisée peuvent donc être multiples :

  • Éviter de redémarrer votre machine pour compiler vos binaires.
  • Disponibilité des outils sur votre machine / Indisponibilité des outils de compilation sur la machine de destination (on trouve rarement des outils de compilation sur des téléphones portables2).
  • Puissances des calculs (la compilation prendra moins de temps sur votre PC de bureau que sur votre appareil mobile3).
  • Licence : Vous voulez compiler à destination d'un système d'exploitation que vous ne possédez pas

Attention: La compilation croisée ne garantie pas que programme fonctionnera, vous devrez toujours faire quelques tests à partir d'un émulateur ou à partir du système d'exploitation final. ...


Lire la suite ...

Ecriture d'un programme pour communiquer avec Trac à l'aide du XML-RPC

Posté le 15. August 2011 dans ProgrammationTags: qt

Temps de lecture: 6 min

Présentation

Ce billet à pour but d'expliquer comment écrire un programme afin de communiquer en XML-RPC avec Trac. Du à un manque d'API on montrera également comment effectuer l'enregistrement d'un utilisateur sur le gestionnaire de ticket à l'aide de Webkit.

L'exemple sera écrit en C++, à l'aide de Qt.

Le programme permettra à partir d'un programme lancé depuis son poste, de :

  • s'enregistrer
  • créer un ticket
  • attaché des fichiers au ticket

Le programme devra garder en mémoire le login et le mot de passe de l'utilisateur pour pouvoir le ré-utiliser par la suite pour la création d'autres ticket. ...


Lire la suite ...

C++/Qt - CMake et Qt

Posté le 26. June 2011 dans ProgrammationTags: qt

Temps de lecture: 5 min

Suite à un billet datant de 2008, je reviens vers vous pour ajouter quelques précisions sur la compilation de programme Qt avec CMake. En effet, pour mon programme XINX, j'ai modifié la chaîne de compilation actuelle utilisant QMake par une chaîne de compilation CMake.

CMake est un puissant générateur de Makefile, il permet de remplacer les anciens (mais pas complètement révolus) autotools. CMake ne remplace donc pas le programme make mais vient se placer en amont.

CMake permet de compiler un programme à différents endroits du dossier des sources, ce qui permet de garder le répertoire des sources propre.

Nous allons considérer dans la suite le dossier projet suivant : ...


Lire la suite ...

C++/Qt - Performance de l'utilisation de QSharedPointer

Posté le 25. January 2011 dans ProgrammationTags: kde, performance, qt

Temps de lecture: 17 min

Présentation

Qt est un framework orienté objet écrit en C++ et permettant de faire des interfaces graphiques. Ce framework est utilisé par le projet KDE depuis ses débuts pour en faire un environnement de bureau très complet.

Qt fournit un ensemble de pointeur intelligent1 permettant de gérer plus facilement la mémoire. Le but est alors de ne plus avoir à supprimer des objets. La suppression se fera soit par un pointeur intelligent soit par le système de hiérarchie d'objet existant en Qt (l'objet père qui supprime l'ensemble des objets fils qui lui sont rattachés).

Qt propose l'ensemble des pointeurs intelligents suivants:

  • QSharedDataPointer / QSharedData : ces deux classes utilisées ensemble permettent d'écrire un objet avec partage implicite. Cela signifie que l'objet fonctionnera comme la classe QString. Tant que l'objet est copié, passé en paramètre, .... l'objet n'est pas dupliqué (tous les objets pointes vers le même espace mémoire). Au moment où l'objet est modifié, l'objet est dupliqué. C'est ce qu'on appelle le COW2.
  • QExplictlySharedDataPointer / QSharedData : QExplicitlySharedDataPointer est une variante de QSharedDataPointer. Ce pointeur intelligent, comme son nom l'indique, est détaché uniquement lorsque la méthode detach() est appelée explicitement. Cette classe permet de faire des objets qui fonctionnent comme des pointeurs mais qui sont utilisés sans la notion de pointeur (le *). La suppression des données partagées se fait donc quand tous les objets ne sont plus utilisés.
  • QScopedPointer : Ce pointeur est le plus simple. Il permet de déclarer un pointeur sur le tas et s'occupe de la destruction de l'objet, lorsque le programme sort de la portée du bloc. Cela permet de ne plus se soucier de la libération du pointeur dans les cas d'erreur (exception, retour avant la fin de la fonction car le fichier n'a pu être ouvert, ...).
  • QSharedPointer : Le pointeur dont on parlera dans la suite de ce billet. Il permet de partager non plus des données (comme le fait QSharedData) mais de partager un pointeur3. Nous allons voir dans la suite du billet, comment simplement utiliser ce pointeur, et les performances de ce pointeur par rapport à un pointeur standard.

Sommaire

...

Lire la suite ...

C++/Qt - Concaténation de chaînes de caractères

Posté le 22. December 2010 dans ProgrammationTags: performance, qt

Temps de lecture: 4 min

Présentation

Qt est un framework orienté objet écrit en C++ et permettant de faire des interfaces graphiques à l’aide de ces widgets. Ce framework est utilisé par le projet KDE depuis ses débuts pour en faire un environnement très complet.

Qt permet donc de faire des interfaces graphiques mais aussi d’accéder à des bases de données SQL, de faire de la communication réseau, une gestion simplifiée des threads, la lecture de fichier XML. Qt intègre aussi le moteur HTML Webkit.

Qt ajoute une couche supplémentaire au C++ permettant de faire de l’introspection de classe un peu plus poussée (comme l’appel d’une méthode dont on ne connaît le nom qu’à l’exécution). Qt permet également la gestion d’évènement par l’intermédiaire d’un système puissant de SIGNALS et de SLOTS.

Dans la suite de cet article nous allons nous concentrer sur une très petite partie de Qt mais qui est utilisée dans beaucoup d’applications écrites en Qt : les chaînes de caractères, et plus précisément, la concaténation de chaînes de caractères. ...


Lire la suite ...

Calcul de la distance entre deux fichiers

Posté le 6. June 2010 dans ProgrammationTags: qt, performance

Temps de lecture: 7 min

Présentation

Suite à un billet sur LinuxFR, où je demandais comment calculer la distance (ou le pourcentage de similitude entre deux logiciels), j'ai obtenu la formule suivante :

distance = 1 - ( C(A) + C(B) - C(AB) ) / Max(C(A), C(B))

où C(X) est la taille du fichier X compressé1.

Après avoir testé les formats gzip, bzip2 et lzma, j'ai conclu que le format de compression le plus performant pour le calcul, est le format lzma, car le dictionnaire avec la mise en commun était le plus gros, et donc le calcul de distance est plus efficace.

Le programme

J'ai donc décidé d'écrire un programme parcourant un dossier (avec plusieurs milliers de fichiers) et de calculer pour toutes les combinaisons des fichiers la distance entre chaque fichier. Ce programme consommant énormément de mémoire, il se peut que pour un grand nombre de fichier, le programme se plante avec une erreur d'allocation de mémoire. ...


Lire la suite ...

Qt - Transformation d'une vue tableau en une vue hiérarchique

Posté le 21. September 2009 dans ProgrammationTags: qt

Temps de lecture: 11 min

Pour visualiser des données internes à l'écran, Nokia/Qt nous propose l'architecture MVC à l'aide des classes QAbstractItemModel et de ses sous classes (QAbstractListModel, QAbstractTableModel, ...). Le but de l'architecture MVC est de séparer la représentation mémoire des données, de l'affichage qu'elles auront.

mvc1

Si les données sont par exemple issue d'une requête SQL, le modèle QSqlQueryModel permet de représenter la sélection SQL, à l'écran dans un composant QTableView. Ces données sont alors représentées sous forme d'un tableau deux dimensions.

tableau ...


Lire la suite ...

Parseur XML

Posté le 31. May 2009 dans ProgrammationTags: performance, qt, xml

Temps de lecture: 6 min

Bonjours à tous,

L'utilisation des fichiers XML est, à ce jour, un fait dans la plupart des logiciels et est fortement à la mode. Une entreprise qui ne fait pas un peu de XML est souvent has-been. On utilise alors le XML à bon ou mauvais escient.

Avantages / Inconvénients

Pourquoi utiliser les fichiers XML ? Les fichiers XML sont, pour commencer, des fichiers textes, il seront donc toujours lisibles, ce qui garantit une meilleur pérennité de l'information. Les fichiers XML sont structurés hiérarchiquement et suivent une syntaxe stricte. Ainsi le XML est lisible informatiquement par les différents langages de programmation existant, pour organiser vos données, en utilisant différents niveaux. Les fichiers XML peuvent être commenté ce qui peut améliorer la lisibilité pour un humain.

Le gros inconvénient du XML est sa verbosité. Pour chaque noeud dans la hiérarchie, il y a une balise de début, et une balise de fin contenant le nom de la balise. Le fichier est moins compact que s'il avait été écrit en binaire. Cela peut poser des problèmes comme alourdir les communications réseaux (ex: pour les webservices). Le fichier est aussi plus long à lire qu'un fichier binaire et peut contenir des erreurs. ...


Lire la suite ...

Paquet Debian et Qt

Posté le 8. September 2008 dans ProgrammationTags: debian, qt

Temps de lecture: 6 min

A titre personnel je fabrique quelques programmes en Qt. Comme j'utilise un système Gnu/Debian, j'ai cherché à fabriquer des paquets pour mon système (plus pour le plaisir qu'autre chose, car la plus grande partie de mes utilisateurs sont sous MS/Windows).

Ce billet explique la création de paquet Gnu/Debian pour des applications Qt 4 utilisant QMake

Installation des paquets

Pour la création des paquets pour des programmes utilisant qmake, il faut cdbs, dh_make, dpkg-buildpackage.

aptitude install cdbs dh-make fakeroot devscripts

Création du paquet

Préparation

Vous pouvez donc choisir un de vos programmes que vous voulez empaqueter. Pour cela vous allez commencer par nettoyer l'arborescence de votre projet pour retirer les fichiers de sauvegarde ainsi que les fichiers de construction (*~ *.o, ...). Ce petit nettoyage va permettre d'avoir un paquet source propre. ...


Lire la suite ...

Mémo Qt

Posté le 21. January 2008 dans ProgrammationTags: qt

Temps de lecture: 1 min

Ceci est un petit mémo pour me permettre de ne pas oublier quelques astuces lors de la programmation avec Qt. En parlant de cela, je me suis commandé le livre suivant : C++ GUI Programming with Qt4.

QAbstractItemModel

  • Lors de l'insertion (avec beginInsertRows()), les éléments insérés ne doivent pas contenir de sous éléments (rowCount() == 0) sous peine de causer des plantages.
  • Un model de donnée interne, pouvant être utilisé avec QAbstractItemModel pour afficher une arborescence et étant capable de se rafraîchir à la lecture d'un fichier, se trouve dans les fichiers filecontentstructure.cpp et filecontentstructure.h

CMake et Qt

Compilation d'une librairie static

add_definitions(-DQT_SHARED)
add_library(xinxplugins STATIC ${xinxplugins_SRCS} ${xinxplugins_MOC_SRCS})

Compilation d'un plugin

dynamique
add_definitions(${QT_DEFINITIONS})
add_definitions(-DQT_PLUGIN)
add_definitions(-DQT_NO_DEBUG)
add_definitions(-DQT_SHARED)
add_library(webplugin SHARED ${webplugin_SRCS} ${webplugin_MOC_SRCS})
static
?

Compilation de fichier RC pour Windows

if(WIN32)
    add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xinx_ico.obj
           COMMAND windres.exe -I${CMAKE_CURRENT_SOURCE_DIR} -o ${CMAKE_CURRENT_BINARY_DIR}/xinx_ico.obj -i${CMAKE_CURRENT_SOURCE_DIR}/${xinx_RCS}
    )
    set(xinx_RESS ${CMAKE_CURRENT_BINARY_DIR}/xinx_ico.obj)
endif(WIN32)

Lire la suite ...