×
Namespaces

Variants
Actions

Usando qmake para compilação condicional

From Nokia Developer Wiki
Jump to: navigation, search
Article Metadata

Compatibilidade
Plataforma(s):
Symbian

Artigo
Criado por User:Rodrigopex em 09 Jul 2009
Última alteração feita por hamishwillee em 13 Jun 2012

Introdução

Atualmente muitos projetos Open Source apresentam para os usuários duas versões: estável e experimental. Isso pode ser feito utilizando um sistema de controle de versão (CV) onde podemos ter um branch com o código estável e outro com o código experimental adicionado. Isso transforma-se num incomodo a partir do momento que o desenvolvedor tem que fazer branches acompanhados de merges. Outra razão pela qual o CV pode não ser muito eficaz é o fato de o código experimental pode modificar estruturas do código estável e isso gera a necessidade da execução de vários testes de regressão após os merges. Há também um custo com a integração de novas funcionalidades, testes de integração serão necessários.

Quando o código experimental está sendo escrito junto ao estável alguns dos testes já são feitos implicitamente como, por exemplo, o de integração. Isso elimina problemas e alguns custos. Neste artigo é abordado o uso de compilação condicional utilizando o qmake e Macros de C++. Se isso é melhor ou pior, fica a critério do desenvolvedor.

QMake e suas variáves

Qmake is a computer program that automates the generation of Makefiles [Wikipedia]

Para entender a aplicação de compilação condicional usando o qmake tem-se que entender algumas minúcias do arquivo .pro, arquivo de configuração usado pelo qmake. Caso já existam os códigos fontes, pode-se gerar o arquivo .pro automaticamente executando o seguinte comando:

#> qmake -project

Para este artigo temos a classe Hello com o método talk(string). Os códigos estão expostos abaixo. Basta executar o comando acima e pronto! Com o .pro gerado podemos conversar... O arquivo gerado é:

######################################################################
# Automatically generated by qmake (2.01a) Sun Jul 12 16:45:10 2009
######################################################################

TEMPLATE = app
TARGET = 
DEPENDPATH += .
INCLUDEPATH += .

# Input
HEADERS += hello.h
SOURCES += hello.cpp main.cpp


Os fontes são conditional-compilation.pro, hello.h, hello.cpp e main.cpp.

hello.h:

#ifndef HELLO_H
#define HELLO_H

#include <stdio.h>

class Hello
{
public:
    Hello();
    void talk(char * words);
};
  1. endif // HELLO_H


hello.cpp:

#include "hello.h"

Hello::Hello()
{
}
void Hello::talk(char *words){
    printf("%s\n", words);
}

main.cpp:

#include "hello.h"

int main(){
    Hello *test = new Hello();
    char word[] = "Hello world!";
    test->talk(word);
    return 0;
}

Muitos detalhes serão suprimidos, só serão explicadas as variáveis que nos interessam aqui. Primeiramente os arquivos .cpp serão listados na variável SOURCES e os arquivos .h serão listados em HEADERS no arquivo conditional-compilation.pro. Com isso já podemos compilar o projeto. A classe Hello tem um método chamado talk que imprime um array de caracteres ainda usando a biblioteca stdio.h. Vamos imaginar agora que é necessário implementar essa classe com o cout da biblioteca iostream. Mas queremos manter a versão estável funcionando. Faremos as seguintes modificações no código fonte.

conditional-compilation.cpp

TEMPLATE = app
TARGET = 
DEPENDPATH += .
INCLUDEPATH += .

# Input
HEADERS += hello.h
SOURCES += hello.cpp main.cpp

experimental {
    message(It was generated the makefile to the experimental project version.)
    DEFINES+=EXPERIMENTAL
    SOURCES+=hello_exp.cpp
}


hello.h:

#ifndef HELLO_H
#define HELLO_H

#include <stdio.h>

#ifdef EXPERIMENTAL
#include <QString>
#include <iostream>
using namespace std;
#endif

class Hello
{
public:
    Hello();
    void talk(char * words);
    #ifdef EXPERIMENTAL
    void talk(QString words);
    #endif
};

#endif // HELLO_H

main.cpp:

#include "hello.h"

int main(){
    Hello *test = new Hello();
    char word[] = "Hello world!";
    test->talk(word);

    #ifdef EXPERIMENTAL
    QString qsword = "Hello world QString";
    test->talk(qsword);
    #endif
    return 0;
}

O arquivo hello_exp.cpp foi adicionado, ele implementa a nova versão do método talk. Mas devemos lembrar que a implementação anterior do método talk deve manter seu funcionamento normal.

hello_exp.cpp

# include "hello.h"

void Hello::talk(QString words){
    cout << qPrintable(words) << endl;
}

Observe nos códigos modificados que os trechos que implementam a versão experimental estão sempre entre #ifdef EXPERIMENTAL ... #endif. Essa é a parte condicional do código. Caso a macro EXPERIMENTAL seja definida em algum lugar, esse código fará parte do código; caso contrário esse trecho desaparece. No arquivo condional-compilation.pro temos um novo trecho que define a macro EXPERIMENTAL e adiciona a lista de arquivos a serem compilados o arquivo extra hello_exp.cpp. Com isso podemos compilar tanto a versão estável quanto a experimental.

Para compilarmos apenas a versão estável basta executar

#> qmake
#> make clean             ...(só para garantir que os código anteriores serão recompilados)
rm -f hello.o main.o
rm -f *~ core *.core
#> make
[...]
#> ./conditional-compilation
Hello world!
#>

Para compilar a versão experimental basta executar:

#> qmake "CONFIG+=experimental"
Project MESSAGE: It was generated the makefile to the experimental project version.
#> make clean
rm -f hello.o main.o hello_exp.o
rm -f *~ core *.core
#> make
[...]
#> ./conditional-compilation
Hello world!
Hello world QString
#>

Esse é um pequeno exemplo ilustrativo de onde podemos extrair as noções básicas do uso de compilação condicional. Isso é usado em algumas áreas de engenharia de software como linhas de produtos de software. Há uma certa discussão com relação ao uso dessa técnica, mas que não vem ao caso. Aqui apenas mostramos como faz, não vamos entrar nessa "disputa". :D

This page was last modified on 13 June 2012, at 10:58.
53 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×