使用 GCJ 編譯 ActiveMQ Classic

連線能力 > 跨語言客戶端 > C 整合 > 使用 GCJ 編譯 ActiveMQ Classic

您可以使用 GCJ 來建置 ActiveMQ Classic 作為一個您可以從 C++ 重複使用的共享函式庫。

原生編譯 ActiveMQ Classic HOWTO

摘要

本文檔描述如何原生編譯 ActiveMQ Classic 以便在 C++ 環境中使用。 本 HOWTO 中使用的 ActiveMQ Classic 版本為 3.2。 若要編譯,您需要具備 Java 和 C/C++ 支援的 GCC 4.0.2 或更高版本。

工具設定

如果您尚未安裝 GCC 4.0.2,則需要下載並建置它。 有關如何建置 GCC 的完整說明,請參閱 GCC 手冊,但以下簡要說明了所涉及的步驟。 GCC 建置步驟假設您已經安裝了較舊的 GCC 編譯器。

  • 將 GCC 解壓縮到任意目錄,例如 /opt/gccbuild,然後建立一個單獨的輸出目錄。 您的目錄結構應該類似於這樣:
    /opt/gccbuild/gcc-4.0.2
    /opt/gccbuild/output
    
  • 前往輸出目錄並執行設定。
    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 中撰寫一個 facade 物件,以處理 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 專案標誌是 The Apache Software Foundation 的商標。版權所有 © 2024,The Apache Software Foundation。 依 Apache License 2.0 授權。