Docker에서 JNA용 리눅스 동적 라이브러리 빌드하기
파일들
다음과 같은 상황이라고 가정한다.
crypto++ 라이브러리를 사용하여 특정한 기능을 제공하는 libcrypt라는 동적 라이브러리를, java에서 jna로 사용하려는 상황이다.
라이브러리 파일이 예시로 다음과 같다고 하고,
// mycrypt.h
#pragma once
#include <cstdlib>
extern "C" {
int DoSomething (int a, int b);
}
// mycrypt.cc
#include <iostream>
#include "mycrypt.h"
__attribute__((constructor)) void init() {
// initialize here
}
__attribute__((destructor)) void fini() {
// finalize here
}
int DoSomething(int a, int b) {
return a + b;
}
이를 사용하는 샘플은 다음과 같다.
// mycryptsample.cc
#include <iostream>
#include "mycrypt.h"
int main (int argc, char ** argv) {
int ret = DoSomething(10, 20);
std::cout << "mycryptsample : " << ret << std::endl;
}
// MyCryptUser.java
import com.sun.jna.Library;
import com.sun.jna.Native;
interface MyCryptLibrary extends Library {
MyCryptLibrary INSTANCE = Native.load("mycrypt", MyCryptLibrary.class);
int DoSomething(int a, int b);
}
public class MyCryptUser {
public static void main(String[] args) {
int ret = MyCryptLibrary.INSTANCE.DoSomething(10, 20);
System.out.println("MyCryptUser: " + ret);
}
}
Dockerfile
아래는 이 코드들을 빌드하고 테스트하고 패키징하는 Dockerfile의 예이다.
FROM ubuntu:16.04 AS builder
WORKDIR /root
RUN apt-get update
RUN apt-get install -y build-essential libcrypto++-dev
COPY . .
RUN g++ -std=c++14 -fPIC -c mycrypt.cc -lcrypto++ -I/usr/include/crypto++
RUN g++ -std=c++14 -shared -o libmycrypt.so mycrypt.o -lcrypto++
RUN g++ -std=c++14 -o mycryptsample mycryptsample.cc -L. -lmycrypt -lcrypto++
FROM ubuntu:16.04 AS testandpackage
VOLUME /output
WORKDIR /deploy
RUN apt-get update
RUN apt-get install -y build-essential openjdk-8-jre openjdk-8-jdk wget libcrypto++9v5
COPY --from=builder /root/libmycrypt.so /deploy/
COPY --from=builder /root/mycrypt.h /deploy/
COPY --from=builder /root/mycryptsample /deploy/
COPY --from=builder /root/MyCryptUser.java /deploy/
COPY --from=builder /root/README.md /deploy/
RUN wget https://repo1.maven.org/maven2/net/java/dev/jna/jna/5.10.0/jna-5.10.0.jar
RUN echo `pwd` > mycrypt.conf
RUN mv mycrypt.conf /etc/ld.so.conf.d/
RUN ldconfig
ENV CLASSPATH="$CLASS_PATH:jna-5.10.0.jar:/usr/local/lib:/usr/local/lib/x86_64-linux-gnu:/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu:."
RUN javac MyCryptUser.java
RUN ./mycryptsample
RUN java MyCryptUser
CMD ./mycryptsample && java MyCryptUser && tar cvjf /output/mycrypt.tar.bz2 mycrypt.h MyCryptUser.java README.md libmycrypt.so
다음과 같은 shell 명령으로 빌드할 수 있고, 빌드 결과가 output이라는 폴더에 만들어진다.
docker build . -t mycryptbuild:0.1.0
docker run -v output:/output mycryptbuild:0.1.0
참조
다음과 같은 문서들을 참조하였음.
- lesstif : 동적 라이브러리(shared library)와 Linker/Loader 이해하기
- lesstif : 공유 라이브러리 의존성(shared library dependencies)을 출력하는 linux ldd 사용법
- Stackoverflow : Automatically executed functions when loading shared libraries
- AskUbuntu : Where does Ubuntu look for shared libraries?
- 꿈많은아이 : 리눅스 공유라이브러리(동적 라이브러리) 생성 및 사용