使用 GCJ 编译 ActiveMQ Classic

连接 > 跨语言客户端 > C 集成 > 使用 GCJ 编译 ActiveMQ Classic

你可以使用 GCJ 构建 ActiveMQ Classic 作为共享库,你可以在 C++ 中重用它。

原生编译 ActiveMQ Classic HOWTO

摘要

本文档描述了如何在 C++ 环境中原生编译 ActiveMQ Classic。本指南中使用的 ActiveMQ Classic 版本是 3.2。要进行编译,你需要 GCC 4.0.2 或更高版本,同时支持 Java 和 C/C++。

工具设置

如果你还没有安装 GCC 4.0.2,你需要下载并构建它。有关如何构建 GCC 的完整说明,请参阅 GCC 手册,但以下是有关步骤的简要说明。GCC 构建步骤假设你已经安装了旧版本的 GCC 编译器。

  • 将 GCC 解压缩到任意目录,例如 /opt/gccbuild,然后创建一个单独的输出目录。你的目录结构应该类似于以下结构;
    /opt/gccbuild/gcc-4.0.2
    /opt/gccbuild/output
    
  • 进入输出目录并运行 configure。
    cd /opt/gccbuild/output
    ../gcc-4.0.2/configure --prefix=/opt/gcc402
                           --enable-shared
                           --enable-threads=posix
                           --enable-languages=c,c++,java
    
  • 运行 make。
    make bootstrap
    make install
    
  • 下载 ActiveMQ Classic 并将 JAR 文件复制到一个新的空目录 /opt/app,包括
    activeio-1.1.jar
    activemq-core-3.2.jar
    commons-logging-1.0.3.jar
    concurrent-1.3.4.jar
    geronimo-spec-j2ee-jacc-1.0-rc4.jar
    geronimo-spec-j2ee-management-1.0-rc4.jar
    geronimo-spec-jms-1.1-rc4.jar
    geronimo-spec-jta-1.0.1B-rc4.jar
    log4j-1.2.8.jar
    

编写粘合代码

直接从 C++ 访问 ActiveMQ Classic 类,或在 Java 中编写一个外观对象来处理 ActiveMQ Classic 的所有启动和关闭逻辑。将粘合文件保存在与 ActiveMQ Classic jar 文件相同的目录中。

一个使用 Java 对象启动 MQ 的 CNI 示例。

Bootstrap.cpp
#include <gcj/cni.h>
#include <iostream>
#include <java/lang/System.h>
#include <java/lang/Throwable.h>
#include <java/io/PrintStream.h>
#include "MQAdapter.h"

using namespace std;

int main(int argc, char* argv\[\])
{
    cout << "Entering main" << endl;
    using namespace java::lang;

    try
    {
        // Create and startup Java VM
        JvCreateJavaVM(NULL) ;
        JvAttachCurrentThread(NULL, NULL) ;

        System::out->println(JvNewStringLatin1("Java println")) ;

        // Start ActiveMQ Classic
        MQAdapter* pAdapter = new MQAdapter() ;
        pAdapter->start() ;

        // Send a message
        pAdapter->send(JvNewStringLatin1("Hello World!")) ;

        // Shutdown ActiveMQ Classic
        pAdapter->stop() ;
     
        JvDetachCurrentThread() ;
    }
    catch( Throwable *t )
    {
        System::err->println(JvNewStringLatin1("Exception")) ;
        t->printStackTrace() ;
    }
}
MQAdapter.java
import org.activemq.*;
import java.util.Hashtable ;
import javax.jms.*;
import javax.naming.*;

public class MQAdapter
{
    private InitialContext         jndiContext ;
    private QueueConnectionFactory factory ;
    private QueueConnection        connection ;
    private QueueSession           session ;
    private QueueSender            sender ;
    private Queue                  queue ;

    public MQAdapter()
    {
    }

    public void start()
    {
        try
        {
            Hashtable props = new Hashtable() ;
            props.put(Context.INITIAL\_CONTEXT\_FACTORY, "org.activemq.jndi.ActiveMQInitialContextFactory") ;
            props.put(Context.PROVIDER_URL, "tcp://127.0.0.1:61616") ;
            props.put("queue.MyQueue", "example.MyQueue") ;

            jndiContext = new InitialContext(props) ;
        
            // Create and configure JMS connection factory
            factory = (QueueConnectionFactory)jndiContext.lookup("ConnectionFactory") ;

            // Lookup Queue
            queue = (Queue)jndiContext.lookup("MyQueue") ;

            // Create a JMS connection
            connection = (QueueConnection)factory.createQueueConnection() ;
            System.out.println("Created connection: " + connection) ;

            // Create a JMS session
            session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE) ;
            System.out.println("Created session: " + session) ;

            // Create JMS sender
            sender  = session.createSender(queue) ;
        }
        catch( Exception e )
        {
            e.printStackTrace() ;

            try
            {
                if( connection != null )
                    connection.close() ;
            } catch( JMSException jmse )
            { /* ignore */ }
        }
    }

    public void stop()
    {
        try
        {
            if( connection != null )
                connection.close() ;
        } catch( JMSException e )
        { /* ignore */ }
    }

    public void send(String msg)
    {
        TextMessage message ;

        try
        {
            message = session.createTextMessage(msg) ;
            sender.send(message) ;
        }
        catch( JMSException e )
        {
            e.printStackTrace() ;
        }
    }
}

编译 Java 和 C++ 代码

Java 代码必须进行 BC 编译,以便能够根据需要动态链接所需的类,有关 BC 编译的更多信息,请参阅参考。使用建议的脚本编译所有 ActiveMQ Classic JAR 文件并创建类映射数据库。

注意

使用 -Bsymbolic 似乎不起作用,请改用 -symbolic。

compile.sh:

#!/bin/sh

# Create new classmap database
gcj-dbtool -n classmap.db

for JAR_FILE in \`find -iname "*.jar"\`
do
    echo "Compiling ${JAR_FILE} to native"
    gcj -shared -findirect-dispatch -fjni -fPIC -Wl,-symbolic -o ${JAR\_FILE}.so ${JAR\_FILE}
    gcj-dbtool -a classmap.db ${JAR\_FILE} ${JAR\_FILE}.so
done
  • 运行上述脚本并设置环境属性 GCJ_PROPERTIES。
    ./compile.sh
    export GCJ_PROPERTIES="gnu.gcj.precompiled.db.path=/opt/app/classmap.db"
    
  • Java 编译 MQAdapter.java
    gcj --classpath=./geronimo-spec-jms-1.1-rc4.jar:./activemq-core-3.2.jar -C MQAdapter.java
    
  • 为 MQAdapter.class 生成 CNI 头文件
    gcjh MQAdapter
    
  • 将 Java 粘合代码打包成 JAR 文件
    fastjar cf MQAdapter.jar MQAdapter.class
    
  • 将 Java JAR 文件原生编译成共享库,并将输出目录添加到 LD_LIBRARY_PATH 中。
    gcj -shared -findirect-dispatch -fjni -fPIC -Wl,-symbolic -o MQAdapter.so MQAdapter.jar
    export LD\_LIBRARY\_PATH=$LD\_LIBRARY\_PATH:/opt/app
    
  • 编译 C++ 代码
    g++ -c Bootstrap.cpp
    
  • 将 Bootstrap 与 Java 代码链接
    gcj -o Bootstrap Bootstrap.o -L /opt/app -lgcj -lstdc++ activeio-1.1.jar.so activemq-core-3.2.jar.so
        commons-logging-1.0.3.jar.so concurrent-1.3.4.jar.so geronimo-spec-jms-1.1-rc4.jar.so
        geronimo-spec-j2ee-management-1.0-rc4.jar.so geronimo-spec-j2ee-jacc-1.0-rc4.jar.so
        geronimo-spec-jta-1.0.1B-rc4.jar.so log4j-1.2.8.jar.so MQAdapter.so
    

现在,如果一切顺利,你应该能够通过 ./Bootstrap 运行该应用程序。

参考

如何使用 GCJ 进行 BC 编译

Linux 上的 Java 状态

Apache, ActiveMQ, Apache ActiveMQ、Apache 羽毛标志和 Apache ActiveMQ 项目标志是 Apache 软件基金会的商标。版权所有 © 2024,Apache 软件基金会。根据 Apache 许可证 2.0 许可。