Veja nesse artigo como utilizar a biblioteca cpptask junto com Ant / Maven para compilar programas e bibliotecas feitas em C/C++.
Figura 1: Java e C++
Introdução
As linguagens Java e C/C++ são amplamente utilizadas na área de TI, e com certeza, muitos desenvolvedores gostariam de integrar suas aplicações C/C++ com o Ant / Maven, a fim de incorporá-los ao processo de build e/ou integração contínua.
Veremos nesse artigo como efetuar esse processo, através da biblioteca cpptask.
Cpptask
Para integrar a compilação do código C/C++ com o Ant/Maven, usaremos a lib cpptask. Para isso, devemos efetuar o download em:
Nota: A versão utilizada é a cpptasks-1.0b5.Esse artigo utilizará a plataforma Solaris como ambiente de desenvolvimento.
Passos:
- Depois de baixar o arquivo (cpptasks-1.0b5.zip), descompacte-o. O diretório cpptasks-1.0b5 será criado.
- Se você procurar, não irá encontrar nenhum arquivo jar. Teremos que gerá-la.
- Note que dentro do diretório cpptasks-1.0b5 existem os seguintes arquivos:
- build.xml
- LICENSE
- NOTICE
- pom.xml
- site
- src
- sun_checks.xml
Ou seja, podemos usar tanto o ant (build.xml), como o maven (pom.xml) para construir a lib.
Usando o ANT
- Verificar se o jar ant.jar está no CLASSPATH (cpptask depende desse jar)
- Entrar no diretório onde o cpptask foi descompactado
- Digitar: ant
- Será criado o diretório target. Dentro de target existe um diretório lib que contém o jar cpptasks.jar
- Adicionar o jar cpptasks.jar no CLASSPATH
Usando o Maven
- Entrar no diretório onde o cpptask foi descompactado
- Digitar: mvn compile
- Digitar: mvn install
- Será criado o diretório target. Dentro desse diretório estará a lib cpptasks-1.0b5.jar.
- Adicionar o jar no CLASSPATH
Nota: Caso haja problemas, incluir o jar no diretório lib dos pacotes do ant.
Primeiro Exemplo
Crie o seguinte build.xml:
Listagem 1: build.xml para compilar programa C
<project name="hello" default="compile">
<taskdef resource="cpptasks.tasks"/>
<target name="compile">
<mkdir dir="target/main/obj"/>
<cc outtype="executable" subsystem="console" outfile="target/hello" objdir="target/main/obj">
<fileset dir="src/" includes="*.c"/>
</cc>
</target>
</project>
No mesmo diretório do build.xml, crie a basta src. Dentro de src, crie o seguinte arquivo c:
Listagem 2: Hello world em C
#include <stdio.h>
int main() {
printf ("\nHello World");
return 1;
}
Agora execute o comando ant no mesmo diretório onde se encontra o arquivo build.xml. Será criada a pasta target, com o binário hello. Ao executá-lo, temos:
Listagem 3: Saída de hello
./hello
HelloWorld
Analisaremos agora os pontos importantes de build.xml:
Listagem 4: taskdef
<taskdef resource="cpptasks.tasks"/>
Adiciona a task CCTask (definida no arquivo de resource cpptasks.tasks), para que possamos utilizar a tag cc.
Listagem 5: task cc
<cc outtype="executable" subsystem="console" outfile="target/hello" objdir="target/main/obj">
<fileset dir="src/" includes="*.c"/>
</cc>
Estamos definindo a compilação dos fontes em C:
- outtype – Define o tipo arquivo de saída. No caso um arquivo executável
- subsystem – Define a natureza do sistema onde será executado. No caso, via console
- outfile – Nome do arquivo de saída
- objdir – Diretório de destino dos arquivos object.
A definição completa encontra-se em: http://ant-contrib.sourceforge.net/cpptasks/antdocs/CCTask.html.
Vejamos agora, outros recursos de cc.
Listagem 6: Exemplo mais complexo de build.xml
<project name="parteC" default="compile">
<taskdef resource="cpptasks.tasks"/>
<target name="compile">
<mkdir dir="utilUnitTest/lib"/>
<cc outtype="shared" subsystem="console" outfile="lib/UtilUnitTest" objdir="utilUnitTest/src" debug="on">
<fileset dir="utilUnitTest/src" includes="*.c"/>
<includepath path="utilUnitTest/include"/>
</cc>
</target>
</project>
Nesse caso, estamos:
- Ativando o modo debug (debug=”on”). Assim erros do gcc serão impressos.
- Definindo a saída como shared, ou seja, biblioteca dinâmica. Ao definir esse tipo de saída, o arquivo gerado terá o nome: libUtilUnitTest.so (note que o prefixo lib e o sufixo .so são adicionados automaticamente)
- usamos <includepath> para informar onde estão os .h usados pelos arquivos .c.
Nota: Ao não definir um compilador default, o gcc será utilizado.
Compilando no Windows ou no Linux
O build.xml a seguir, demonstra como utilizar compilação condicional multiplataforma:
Listagem 7: build multi-plataforma
<?xml version="1.0"?>
<project name="Hello" default="hello" basedir=".">
<taskdef resource="cpptasks.tasks"/>
<typedef resource="cpptasks.types"/>
<target name="init">
<condition property="cc" value="msvc">
<os family="windows"/>
</condition>
<condition property="cc" value="gcc">
<os family="unix"/>
</condition>
</target>
<target name="hello" depends="init">
<cc name="${cc}" outfile="hello">
<fileset dir="." includes="hello.c"/>
</cc>
</target>
</project>
Observe que, nesse exemplo, o compilador a ser executado (gcc no Unix ou msvc no Windows), é definido através da task condition do Ant, onde definimos o compilador padrão a partir do sistema onde ele será executado. (build.xml extraído de http://www.drdobbs.com/cpp/ant-cpptasks-multiplatform-cc-projects/184405433)
Integrando Ant Com Maven
Podemos também utilizar o Maven para gerar o build dos programas C/C++. Para isso, basta utilizar o plugin maven-antrun. Por exemplo:
Listagem 8: Hello World com Maven: pom.xml
<project>
<modelVersion>4.0.0</modelVersion>
<artifactId>my-test-app</artifactId>
<groupId>my-test-group</groupId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<dependencies>
<dependency>
<groupId>cpptasks-1.0b5</groupId>
<artifactId>cpptasks</artifactId>
<version>1.0b5</version>
<scope>system</scope>
<systemPath>/export/home/ms27817/dev/cpptasks-1.0b5/target/cpptasks-1.0b5.jar</systemPath>
</dependency>
</dependencies>
<executions>
<execution>
<id>cpp source</id>
<phase>compile</phase>
<configuration>
<target>
<ant antfile="${basedir}/build.xml">
<target name="compile"/>
</ant>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
O arquivo pom.xml utiliza o plugin maven-antrun-plugin, que permite executar comandos Ant dentro do Maven.
As partes mais importantes são:
Listagem 9: Dependência de CppTask
<dependency>
<groupId>cpptasks-1.0b5</groupId>
<artifactId>cpptasks</artifactId>
<version>1.0b5</version>
<scope>system</scope>
<systemPath>/export/home/ms27817/dev/cpptasks-1.0b5/target/cpptasks-1.0b5.jar</systemPath>
</dependency>
Onde informamos ao Maven que o jar cpptasks-1.0b5.jar é uma dependência.
Listagem 10: Invocando o ANT
<target>
<ant antfile="${basedir}/build.xml">
<target name="compile"/>
</ant>
</target>
Aqui, o arquivo build.xml definido na Listagem 1 é utilizado. Portanto, a task ant irá executar a target compile do build.xml para gerar o binário de hello world.
Conclusão
A biblioteca cpptask é realmente muito útil, ao permitir que código C/C++ seja integrado as ferramentas Ant/Maven, substituindo o make, e com isso favorecendo o build integrado do sistema.
Obrigado e até a próxima!