segunda-feira, 9 de dezembro de 2013

C++ e Maven: nar-maven-plugin

No meu trabalho, desenvolvo códigos em C, C++ e Java principalmente, além de outras linguagens. Para Java, já não consigo mais dispensar a utilização do Maven. Pesquisei sobre como usar Maven também para compilar códigos em C e C++. Foi então que encontrei o nar-maven-plugin.

Este plugin para Maven está atualmente ativo graças a uma grupo de desenvolvedores, mas nem sempre foi assim: ele esteve meio parado por um tempo e seu desenvolvedor original doou o código para um outro grupo de desenvolvedores continuar o trabalho. Tutoriais sobre o plugin ainda são escassos e muitos fazem referência a uma versão mais antiga e algumas configurações não se aplicam mais para a versão atual. O mailing list no momento tem poucas postagens, mas quando o assunto é relevante, os desenvolvedores estão sempre atentos e respondem com rapidez.

Uma outra opção é usar o native-maven-plugin. Este tem a sua última versão, a 1.0-alpha-7, liberada em março de 2011. Os tutoriais sobre este plugin são poucos e achei sua configuração pouco intuitiva. Por todos estes motivos desfavoráveis, optei por usar o nar-maven-plugin, principalmente por estar mais ativo no momento e ser mais um pouco mais fácil configurá-lo.

Objetivos dos Testes

A intenção aqui é criar dois projetos em C++, sendo um para gerar uma biblioteca estática e outro com uma biblioteca dinâmica que utiliza a biblioteca estática.

Os projetos são bem simples e estão estruturados de acordo com Maven 3. O foco está na utilização do nar-maven-plugin e não exatamente na utilização do Maven. Portanto, é esperado que se conheça o básico sobre Maven e sua utilização.

Preparação para os Testes

Os testes foram realizados no Windows 7 64 bits utilizando os seguintes sistemas:
  • Maven 3
  • Mingw 4.8.1
  • Nar-maven-plugin-3.0.0
    Tanto para o Maven quanto para o Mingw, os diretórios de instalação (com \BIN) devem ser incluídos manualmente no PATH do Windows.

    O nar-maven-plugin será baixado automaticamente pelo Maven de acordo com a configuração apresentada abaixo.

    Download

    O código dos projetos usados para testes estão disponíveis para download. São simples mas servem de modelo para evoluir para projetos maiores.


    Projeto Biblioteca Estática

    Este projeto serve de base para os demais. Abaixo, o arquivo pom.xml do projeto da biblioteca estática é apresentado com a configuração mínima para a utilização do nar-maven-plugin.

    <project xmlns="http://maven.apache.org/POM/4.0.0" 
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>prototype</groupId>
        <artifactId>lib-project</artifactId>
        <version>1.0-SNAPSHOT</version>
      
        <!-- Importante que a opção JAR seja substituída por NAR -->
        <packaging>nar</packaging>
    
        <name>lib-project</name>
    
        <!-- Repositório onde está armazenado o plugin -->
        <pluginRepositories>
            <pluginRepository>
                <id>Sonatype OSS</id>
                <url>http://oss.sonatype.org/content/groups/public</url>
            </pluginRepository>
        </pluginRepositories>
    
        <build>
            <plugins>            
                <plugin>
                    <groupId>com.github.maven-nar</groupId>
                    <artifactId>nar-maven-plugin</artifactId>
                    <version>3.0.0</version>
                    <extensions>true</extensions>
                    <configuration>
                        <!-- Importante definir o nome do compilador C++ caso não seja 
                             o default definido pelo NAR plugin de acordo com a plataforma. 
                             No caso da plataforma Windows, o default é o
                             Microsoft Visual C++. -->                                                                                                   
                        <cpp>                                                        
                            <name>g++</name>  
                        </cpp>
                        <!-- Idem para o linker -->             
                        <linker>
                            <name>g++</name>
                        </linker>
                        <!-- Definir o tipo de binário gerado, neste caso uma biblioteca estática -->
                        <libraries>
                            <library>
                                <type>static</type>
                            </library>
                        </libraries>                    
                    </configuration>                
                </plugin>
            </plugins>
        </build>
        
    </project>
    

    Alguns pontos devem ser observados aqui sobre o arquivo pom.xml:
    1. A configuração de packaging deve ser alterada de JAR para NAR (em letras minúsculas lá no XML), caso contrário o plugin não funcionará;
    2. A localização do repositório do plugin deve ser especificada; desde dezembro de 2013, o plugin tem sido armazenado no Sonatype OSS.
    3. O compilador padrão do plugin é de acordo com a plataforma: para Windows, o padrão é o Microsoft Visual C++ e portanto, caso o exemplo seja utilizado com este compilador, não é necessário definir o nome. Como o exemplo aqui está usando o Mingw, temos que definir o nome do compilador e linker como mostra a configuração no arquivo XML.
    4. Determinar o tipo de arquivo binário gerado, nesta caso uma biblioteca estática.
    Ainda, vale a pena citar a estrutura de arquivos que o plugin espera: por convenção, os arquivos fontes devem estar na pasta \src\main\c++ e os arquivos *.H que acompanham a biblioteca estática (e usados pela biblioteca dinâmica) devem para estar na pasta \src\main\include. É possível modificar ou acrescentar novas pastas. Consulte as opções de configuração oferecidas pelo plugin no site do projeto.

    Uma vez a compilação ocorra com sucesso, o plugin compacta a biblioteca estática e todos os arquivos contidos na pasta \src\main\include do projeto num único arquivo com a extensão NAR e os instala no repositório maven local.

    Projeto Biblioteca Dinâmica

    O arquivo pom.xml deste projeto é basicamente o mesmo do projeto anterior, com alteração no tipo de binário gerado e incluindo a dependência do projeto anterior para 'linkar'.

    <project xmlns="http://maven.apache.org/POM/4.0.0" 
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>prototype</groupId>
        <artifactId>shared-project</artifactId>
        <version>1.0-SNAPSHOT</version>
      
        <packaging>nar</packaging>
    
        <name>shared-project</name>
    
        <!-- Repositório onde está armazenado o plugin -->
        <pluginRepositories>
            <pluginRepository>
                <id>Sonatype OSS</id>
                <url>http://oss.sonatype.org/content/groups/public</url>
            </pluginRepository>
        </pluginRepositories>
    
        <dependencies>
            <!--  dependência do projeto biblioteca estática  -->
            <dependency>           
                <groupId>prototype</groupId>
                <artifactId>lib-project</artifactId>
                <version>1.0-SNAPSHOT</version>
                <!-- Importante definir o tipo como NAR -->
                <type>nar</type>
            </dependency>
        </dependencies>
      
        <build>
            <plugins>            
                <plugin>
                    <groupId>com.github.maven-nar</groupId>
                    <artifactId>nar-maven-plugin</artifactId>
                    <version>3.0.0</version>
                    <extensions>true</extensions>
                    <configuration>                                                
                        <cpp>                                                        
                            <name>g++</name>  
                        </cpp>             
                        <linker>
                            <name>g++</name>
                        </linker>
                        <!-- Gera binário como biblioteca dinâmica -->
                        <libraries>
                            <library>
                                <type>shared</type>
                            </library>
                        </libraries>                    
                    </configuration>                
                </plugin>
            </plugins>
        </build>
        
    </project>
    

    Note que os arquivos *.H da biblioteca estática não precisam ser colocados explicitamente no projeto, conforme explicado anteriormente. Ao compilar um projeto que use esta dependência, o plugin descompacta o arquivo NAR da biblioteca estática e automaticamente inclui os arquivos *.H no caminho de pesquisa para o compilador. O mesmo acontece com o binário da biblioteca estática usado pelo linker.

    Considerações Finais

    A configuração do arquivo pom.xml para compilar código em C++ é muito simples com o nar-maven-plugin.

    O nar-maven-plugin recentemente voltou a ser mantido por um grupo de desenvolvedores e seu mailing list está ativo.

    A utilização do plugin é mais interessante quando se tem código Java que faz acesso código em C++ (ou em C) via JNI; o plugin é capaz de gerar automaticamente os headers e compilar juntos tanto o código Java quando o código em C++. Vou apresentar uma exemplo no próximo artigo.

    Nenhum comentário:

    Postar um comentário