使用 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
运行该应用程序。