使用 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
來執行應用程式。