ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • PDFium 라이브러리 삽질기 - 3
    Linux 2019. 12. 11. 17:15

    PDFium 라이브러리 삽질기 - 3

    RPM 패키징 및 gdal 함께 사용하기 (1)

    작성일자: 2019년 12월 11일

    최종수정: 2019년 12월 13일

    작성자: N3


    1. gdal 과 함께 빌드하기

    gdal 에서 사용하기 위해 빌드 테스트를 해 본다.

    사용한 버전은 gdal 2.3.2 버전이다.


    $ cd ~/pdfium

    $ mkdir include lib

    $ cd include

    $ ln -sf ~/pdfium/public pdfium

    $ cd ../lib

    $ ln -sf ../out/shared/*.so .


    $ cd ~/gdal-2.3.2

    $ ./configure \

    ..

    --with-pdfium=~/pdfium/ \ 

    ..


    checking for pdfium... no

    configure: error: pdfium requested but not found


    gdal 의 configure 에서 with-pdfium 설정시 pdfium  의 유무를 판단하는 코드를 살펴 본다.

    echo '#include <fpdfview.h>' > testpdfium.cpp

    echo '#include <core/include/fpdfapi/fpdf_page.h>' >> testpdfium.cpp

    echo 'int main(int argc, char** argv) { FPDF_InitLibrary(); FPDF_DestroyLibrary(); return 0; } ' >> testpdfium.cpp


     TEST_CXX_FLAGS="-std=c++0x"
     ${CXX} ${CXXFLAGS} ${CPPFLAGS} $TEST_CXX_FLAGS testpdfium.cpp -o testpdfium ${TEST_PDFIUM_INC} ${PDFIUM_LIB}

    해당 코드를 앞에서 테스트했던 코드로 변경해서 테스트 해 보면....

    testpdfium.cpp:2:10: fatal error: core/include/fpdfapi/fpdf_page.h: 그런 파일이나 디렉터리가 없습니다
     #include <core/include/fpdfapi/fpdf_page.h>


    위 헤더 include 를 삭제한다. 그리고 테스트를 위한 링크 라이브러리 옵션을 추가한다.


    --with-pdfium-extra-lib-for-test="-lpthread -lm -lc -lstdc++ -lz -ljpeg -lopenjp2 -llcms2 -lpng"



    정상적으로 빌드 테스트되는 것을 확인할 수 있다. 이제 빌드해 본다.


    $ make

    In file included from gdal_pdf.h:53,

                     from pdfdataset.cpp:36:

    pdfsdk_headers.h:119:10: fatal error: core/include/fpdfapi/fpdf_page.h: 그런 파일이나 디렉터리가 없습니다

     #include <core/include/fpdfapi/fpdf_page.h>



    gdal 에서 사용하고 있는 pdfium 의 헤더 경로가 최신 pdfium 과 다르다.

    앞의 테스트코드 처럼 해당 코드에서 위 헤더추가를 모두 제거해준다.

    iff -urN gdal-2.3.2-fedora/configure gdal-2.3.2-pdfium/configure

    --- gdal-2.3.2-fedora/configure 2019-12-10 13:45:09.745538100 +0900

    +++ gdal-2.3.2-pdfium/configure 2019-12-10 13:54:50.597897767 +0900

    @@ -34698,7 +34698,6 @@

         if test "x$with_pdfium_lib" = "x" ; then

             rm -f testpdfium.*

             echo '#include <fpdfview.h>' > testpdfium.cpp

    -        echo '#include <core/include/fpdfapi/fpdf_page.h>' >> testpdfium.cpp

             echo 'int main(int argc, char** argv) { FPDF_InitLibrary(); FPDF_DestroyLibrary(); return 0; } ' >> testpdfium.cpp

             TEST_CXX_FLAGS="-std=c++0x"

             if test ! -z "`uname | grep Darwin`" ; then

    diff -urN gdal-2.3.2-fedora/frmts/pdf/pdfsdk_headers.h gdal-2.3.2-pdfium/frmts/pdf/pdfsdk_headers.h

    --- gdal-2.3.2-fedora/frmts/pdf/pdfsdk_headers.h        2018-09-21 18:04:33.000000000 +0900

    +++ gdal-2.3.2-pdfium/frmts/pdf/pdfsdk_headers.h        2019-12-10 13:53:44.849271839 +0900

    @@ -116,9 +116,9 @@

     #include <cstring>

     //#include <fpdfsdk/include/fsdk_define.h>

     #include <fpdfview.h>

    -#include <core/include/fpdfapi/fpdf_page.h>

    -#include <core/include/fpdfapi/fpdf_objects.h>

    -#include "fpdfsdk/include/fsdk_rendercontext.h"

    +//#include <core/include/fpdfapi/fpdf_page.h>

    +//#include <core/include/fpdfapi/fpdf_objects.h>

    +//#include "fpdfsdk/include/fsdk_rendercontext.h"

     #endif // HAVE_PDFIUM


     #endif


    수정 후, 다시 빌드 해 본다.

    ..

    pdfobject.h:313:9: error: ‘CPDF_Object’ does not name a type; did you mean ‘PSObject’?

             CPDF_Object* m_po;

             ^~~~~~~~~~~

    ..


    삽질과 서핑 도중 아래의 선배 삽질러를 찾았다.


    gdal 3.1(최신 소스코드) 에 pdfium 을 링크하기 위해  pdfium 을 패치한 내용들이다. 아래 링크는 clang 을 사용하며, static 라이브러리를 생성한다.


    몇 개의 패치코드는 살펴볼 필요가 있다.



     위 링크의 내용들을 참조하고 gdal 3.1 의 pdf 포맷 지원 코드를 현재 2.3.2 코드로 백포팅하기로 한다. 

    위 코드로 업그레이드하면, 관련되어서 업그레이드할 것들이 많다.


    gdal 의 pdfium 최신 패치 확인하기



    일단 URL 및 소스와 패치만 확인하고 패치코드 일부를 적용한 pdfium rpm 패키지를 만들어 본다.


    gdal 과 함께  컴파일하는 것은 다음 삽질과정으로 남겨두고, gdal 테스트를 위해 먼저 pdfium 을 패키징해서 시스템에 설치해둔다.


    2.  CentOS 7 용 PDFium RPM 패키지 만들기


    이제 삽질한 파일들과 내용들을 참조하여 CentOS 7 용 RPM 패키지로 만들어 본다. 

    패키지 이름은 대충 libpdfium 로 한다.

    라이브러리 버전을 확인할 수 없어 일단은 chromium/3989 를 사용했다. 


    정적 라이브러리를 위한 옵션

    # Build arguments go here.

    # See "gn args <out_dir> --list" for available build arguments.

    is_official_build       = true

    pdf_is_standalone   = true                 # Set for a non-embedded build.

    pdf_is_complete_lib = true                 # Static Library - libpdfium.a

    pdf_enable_xfa      = false                # XFA support enabled.

    pdf_enable_v8       = false                # Javascript support enabled.

    pdf_use_skia        = false                # Avoid skia backend experiment.

    pdf_use_skia_paths  = false                # Avoid other skia backend experiment.


    pdf_bundle_freetype = true

    use_system_freetype = false


    clang_use_chrome_plugins = false


    use_goma            = false

    use_custom_libcxx   = false

    use_sysroot         = false

    use_rtti            = true


    is_component_build  = false                # Dynamic Library - libpdfium.so

    is_debug            = false                # Enable debugging features.

    is_clang            = false                # Avoid dependency hell.


    use_system_zlib     = true

    use_system_libpng   = true

    use_system_lcms2    = true

    use_system_libjpeg  = true

    use_libjpeg_turbo   = true

    use_system_libopenjpeg2 = true



    동적 라이브러리를 위한 빌드

    # Build arguments go here.

    # See "gn args <out_dir> --list" for available build arguments.

    is_official_build       = true

    pdf_is_standalone   = true                  # Set for a non-embedded build.

    pdf_is_complete_lib = false                 # Static Library

    is_component_build  = true                  # Dynamic Library


    pdf_enable_xfa      = false                 # XFA support enabled.

    pdf_enable_v8       = false                 # Javascript support enabled.

    pdf_use_skia        = false                 # Avoid skia backend experiment.

    pdf_use_skia_paths  = false                 # Avoid other skia backend experiment.


    pdf_bundle_freetype = true

    use_system_freetype = false


    clang_use_chrome_plugins = false


    use_goma            = false

    use_custom_libcxx   = false

    use_sysroot         = false

    use_rtti            = true


    is_debug            = false                 # Enable debugging features.

    is_clang            = false                 # Avoid dependency hell.


    use_system_zlib     = true

    use_system_libpng   = true

    use_system_lcms2    = true

    use_system_libjpeg  = true

    use_libjpeg_turbo   = true

    use_system_libopenjpeg2 = true



    libpdfium.spec

    %global commit 26cd122a8d10d33091bac50b025df919405a0950

    %global shortcommit %(c=%{commit}; echo ${c:0:7})

    %global chromium_rev   "chromium/3989"


    Name:           libpdfium

    Version:        0.0.3989

    Release:        1%{?dist}

    Summary:        PDF generation and rendering library


    Group:          Development/Libraries

    License:        BSD 3-clause

    URL:            https://pdfium.googlesource.com/pdfium/

    Source0:        .

    # Static Build Argument

    Source1:        pdfium-static-args.gn

    Source2:        pdfium-shared-args.gn


    BuildRoot:      %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)


    BuildRequires:  zlib-devel

    BuildRequires:  libpng-devel

    BuildRequires:  libjpeg-turbo-devel

    BuildRequires:  openjpeg2-devel > 2.3.0

    BuildRequires:  lcms2-devel

    BuildRequires:  devtoolset-8-gcc-c++

    BuildRequires:  git


    Requires:       zlib

    Requires:       libpng

    Requires:       libjpeg-turbo

    Requires:       openjpeg2

    Requires:       lcms2


    %description

    Used in Chrome for displaying PDFs and print preview. Used in Android for PDF rendering


    %package devel

    Summary: Libraries and headers for pdfium

    Group: Development/Libraries

    Requires: %{name}%{?_isa} = %{version}-%{release}


    %description devel

    You should install the libpdfium-devel package if you would like to

    compile applications based on pdfium.


    %prep


    %build


    ## Change GCC

    ##scl enable devtoolset-8 bash


    export DEPOT_TOOLS_URL="https://chromium.googlesource.com/chromium/tools/depot_tools.git"

    export PDFIUM_URL="https://pdfium.googlesource.com/pdfium.git"


    mkdir -p %{name}

    cd %{name}

    export CURDIR=`pwd`

    export DEPOT_TOOLS_DIR=$CURDIR/depot_tools

    if [ ! -d "$DEPOT_TOOLS_DIR" ]; then
       git clone "$DEPOT_TOOLS_URL"  depot_tools
    else
       pushd $DEPOT_TOOLS_DIR
       git checkout master
       git pull
       popd
    fi

    export PATH="$DEPOT_TOOLS_DIR:$PATH"

    # Checkout sources
    # From https://pdfium.googlesource.com/pdfium/
    gclient config --unmanaged "$PDFIUM_URL"

    # Tested Revision
    gclient sync --revision="$chromium_rev"

    # Current Revision
    ##gclient sync

    ## Static Build
    pushd pdfium
    mkdir -p out/static
    cp %{SOURCE1} out/static/args.gn
    gn gen out/static

    # Test Build Error
    ##ninja -C out/static pdfium_all
    ninja -C out/static pdfium

    ## Shared Build
    mkdir -p out/shared
    cp %{SOURCE2} out/shared/args.gn
    gn gen out/shared
    ##ninja -C out/shared pdfium_all
    ninja -C out/shared pdfium
    popd

    %install
    mkdir -p %{buildroot}/%{_includedir}/pdfium
    mkdir -p %{buildroot}/%{_libdir}

    cd %{name}/pdfium

    # Header Install
    HEADER_SUBDIRS="build fpdfsdk core/fxge core/fxge/agg core/fxge/dib core/fpdfdoc core/fpdfapi/parser core/fpdfapi/page core/fpdfapi/render core/fxcrt third_party/agg23 third_party/base third_party/base/allocator/partition_allocator third_party/base/numerics"

    cp -r public %{buildroot}/%{_includedir}/pdfium
    for subdir in $HEADER_SUBDIRS; do
        mkdir -p "%{buildroot}/%{_includedir}/pdfium/$subdir"
        cp "$subdir"/*.h  "%{buildroot}/%{_includedir}/pdfium/$subdir"
    done
    # Static Library Install
    install -m 0644 out/static/obj/libpdfium.a %{buildroot}%{_libdir}/libpdfium.a

    # Shared Library Install
    install -m 0755 out/shared/*.so %{buildroot}%{_libdir}/

    %clean
    rm -rf %{buildroot}

    %pre

    %postun

    %files
    %defattr(-,root,root,-)
    %doc
    %{_libdir}/*.so

    %files devel
    %defattr(-,root,root,-)
    %{_includedir}/pdfium
    %{_libdir}/libpdfium.a

    %changelog
    * Wed Dec 11 2019 N3 <n3syskr@gmail.com> - 0.0.0-1
    - initial build


    헤더파일과 정적 라이브러리는 devel 패키지로 따로 분리하였다.


    gdal 과 빌드하기 위해 위에서 참조한 URL 로부터 pdfium 패치를 가져와 다시 빌드할 것이다.


    pdfium 패치

    diff -urN pdfium/core/fpdfapi/page/cpdf_occontext.cpp pdfium-a/core/fpdfapi/page/cpdf_occontext.cpp

    --- pdfium/core/fpdfapi/page/cpdf_occontext.cpp 2019-12-11 15:41:16.595645562 +0900

    +++ pdfium-a/core/fpdfapi/page/cpdf_occontext.cpp       2019-12-11 15:41:52.535538284 +0900

    @@ -181,7 +181,7 @@

       return bState;

     }


    -bool CPDF_OCContext::CheckObjectVisible(const CPDF_PageObject* pObj) const {

    +bool CPDF_OCContextInterface::CheckObjectVisible(const CPDF_PageObject* pObj) const {

       for (size_t i = 0; i < pObj->m_ContentMarks.CountItems(); ++i) {

         const CPDF_ContentMarkItem* item = pObj->m_ContentMarks.GetItem(i);

         if (item->GetName() == "OC" &&

    diff -urN pdfium/core/fpdfapi/page/cpdf_occontext.h pdfium-a/core/fpdfapi/page/cpdf_occontext.h

    --- pdfium/core/fpdfapi/page/cpdf_occontext.h   2019-12-11 15:41:16.596645587 +0900

    +++ pdfium-a/core/fpdfapi/page/cpdf_occontext.h 2019-12-11 15:42:16.940144477 +0900

    @@ -17,15 +17,21 @@

     class CPDF_Document;

     class CPDF_PageObject;


    -class CPDF_OCContext final : public Retainable {

    +class CPDF_OCContextInterface : public Retainable {

    +    public:

    +        virtual ~CPDF_OCContextInterface() = default;

    +        virtual bool CheckOCGVisible(const CPDF_Dictionary* pOCGDict) const = 0;

    +        virtual bool CheckObjectVisible(const CPDF_PageObject* pObj) const;

    +};

    +

    +class CPDF_OCContext : public CPDF_OCContextInterface {

      public:

       enum UsageType { View = 0, Design, Print, Export };


       template <typename T, typename... Args>

       friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);


    -  bool CheckOCGVisible(const CPDF_Dictionary* pOCGDict) const;

    -  bool CheckObjectVisible(const CPDF_PageObject* pObj) const;

    +  bool CheckOCGVisible(const CPDF_Dictionary* pOCGDict) const override;


      private:

       CPDF_OCContext(CPDF_Document* pDoc, UsageType eUsageType);

    diff -urN pdfium/core/fpdfapi/render/cpdf_renderoptions.h pdfium-a/core/fpdfapi/render/cpdf_renderoptions.h

    --- pdfium/core/fpdfapi/render/cpdf_renderoptions.h     2019-12-11 15:41:16.596645587 +0900

    +++ pdfium-a/core/fpdfapi/render/cpdf_renderoptions.h   2019-12-11 15:41:52.535538284 +0900

    @@ -56,16 +56,16 @@

       void SetDrawAnnots(bool draw) { m_bDrawAnnots = draw; }

       bool GetDrawAnnots() const { return m_bDrawAnnots; }


    -  void SetOCContext(RetainPtr<CPDF_OCContext> context) {

    +  void SetOCContext(RetainPtr<CPDF_OCContextInterface> context) {

         m_pOCContext = context;

       }

    -  const CPDF_OCContext* GetOCContext() const { return m_pOCContext.Get(); }

    +  const CPDF_OCContextInterface* GetOCContext() const { return m_pOCContext.Get(); }


      private:

       Type m_ColorMode = kNormal;

       bool m_bDrawAnnots = false;

       Options m_Options;

    -  RetainPtr<CPDF_OCContext> m_pOCContext;

    +  RetainPtr<CPDF_OCContextInterface> m_pOCContext;

     };


     #endif  // CORE_FPDFAPI_RENDER_CPDF_RENDEROPTIONS_H_
    diff -urN pdfium/core/fpdfdoc/cpdf_annotlist.cpp pdfium-a/core/fpdfdoc/cpdf_annotlist.cpp
    --- pdfium/core/fpdfdoc/cpdf_annotlist.cpp      2019-12-11 15:41:16.596645587 +0900
    +++ pdfium-a/core/fpdfdoc/cpdf_annotlist.cpp    2019-12-11 15:41:52.536538309 +0900
    @@ -246,7 +246,7 @@

         if (pOptions) {
           const CPDF_Dictionary* pAnnotDict = pAnnot->GetAnnotDict();
    -      const CPDF_OCContext* pOCContext = pOptions->GetOCContext();
    +      const auto pOCContext = pOptions->GetOCContext();
           if (pAnnotDict && pOCContext &&
               !pOCContext->CheckOCGVisible(
                   pAnnotDict->GetDictFor(pdfium::annotation::kOC))) {


    앞의 삽질에서 동적 라이브러리로 빌드하는 경우, icu libicuuc.so 파일이 생긴다.

    이 라이브러리 이름이 시스템의 icu 라이브러리 이름과 충돌하며 API 도 완전히 호환되지 않는다.

    그래서, 생성되는 라이브러리의 이름을 변경하기로 삽질해보자.


    먼저, third_party/icu 폴더로 이동한다.


    config.gni 파일을 열고 다음 변수를 추가한다.

    declare_args() {

      # Tells icu to load an external data file rather than rely on the icudata

      # being linked directly into the binary.

      icu_use_data_file = true

      icu_rename = false

    }


    그리고, BUILD.gn 파일에 다음을 추가한다.

    is_fuchsia 는 운영체제가 구글의 자체 운영체제인지 묻는 옵션이다. 이 옵션을 건들지 말고, 새로운 옵션을 추가해 이름만 수정한다.

    ..

      if (is_fuchsia || icu_rename) {

        # Fuchsia puts its own libicui18n.so in /system/lib where we need to put our

        # .so when doing component builds, so we need to give this a different name.

        output_name = "icui18n_cr"

      }

    ..

      if (is_fuchsia || icu_rename) {

        # Fuchsia puts its own libicuuc.so in /system/lib where we need to put our

        # .so when doing component builds, so we need to give this a different name.

        output_name = "icuuc_cr"

      }



    전체 icu 라이브러리 이름 변경 패치

    diff -urN pdfium/third_party/icu/BUILD.gn pdfium-icu/third_party/icu/BUILD.gn

    --- pdfium/third_party/icu/BUILD.gn     2019-12-11 15:31:28.283025785 +0900

    +++ pdfium-icu/third_party/icu/BUILD.gn 2019-12-11 16:36:25.528721775 +0900

    @@ -630,7 +630,7 @@

       configs += [ ":icu_code" ]

       public_configs = [ ":icu_config" ]


    -  if (is_fuchsia) {

    +  if (is_fuchsia || icu_rename) {

         # Fuchsia puts its own libicui18n.so in /system/lib where we need to put our

         # .so when doing component builds, so we need to give this a different name.

         output_name = "icui18n_cr"

    @@ -1080,7 +1080,7 @@


       defines += [ "U_ICUDATAENTRY_IN_COMMON" ]


    -  if (is_fuchsia) {

    +  if (is_fuchsia || icu_rename) {

         # Fuchsia puts its own libicuuc.so in /system/lib where we need to put our

         # .so when doing component builds, so we need to give this a different name.

         output_name = "icuuc_cr"

    diff -urN pdfium/third_party/icu/config.gni pdfium-icu/third_party/icu/config.gni

    --- pdfium/third_party/icu/config.gni   2019-12-11 15:31:28.645034782 +0900

    +++ pdfium-icu/third_party/icu/config.gni       2019-12-11 16:35:57.330023671 +0900

    @@ -6,4 +6,5 @@

       # Tells icu to load an external data file rather than rely on the icudata

       # being linked directly into the binary.

       icu_use_data_file = true

    +  icu_rename = false

     }



    동적 라이브러리를 빌드할 때,

    icu_rename = true

    옵션을 추가해서 빌드하면, 

    libicuuc.so 파일의 이름이 libicuuc_cr.so  이름으로 생성되어 기존 icu 라이브러리와 충돌하지 않게 할 수 있다.



    RPM 패키지을 만들고 로컬 인스톨해둔다.

    Dependencies Resolved


    =====================================================================================

     Package                     Arch               Version                       Repository         Size

    =====================================================================================

    Installing:

     libpdfium-devel             x86_64             0.0.3989-1.el7                n3sys             3.4 M

    Installing for dependencies:

     libpdfium                   x86_64             0.0.3989-1.el7                n3sys             1.9 M


    Transaction Summary

    =====================================================================================

    Install  1 Package (+1 Dependent package)


    Total download size: 5.3 M

    Installed size: 19 M


    RedHat 계열에서 아래 소스 rpm 을 사용하면 된다.


    테스트 시작 시점에 리비전 번호는 3989 였다.  현재는 3999다.


    최신 버전으로 테스트하려면, libpdfium.spec 파일에서 해당 리비전 번호를 수정해서 테스트하면 된다.

    %global chromium_rev   "chromium/3989"

    ...

    gclient sync --revision="$chromium_rev"



    $ rpmbuild --rebuild libpdfium-0.0.3989-1.el7.src.rpm


    Checking for unpackaged file(s): /usr/lib/rpm/check-files /home/respiro/rpmbuild/BUILDROOT/libpdfium-0.0.3989-1.el7.x86_64

    Wrote: /home/respiro/rpmbuild/SRPMS/libpdfium-0.0.3989-1.el7.src.rpm

    Wrote: /home/respiro/rpmbuild/RPMS/x86_64/libpdfium-0.0.3989-1.el7.x86_64.rpm

    Wrote: /home/respiro/rpmbuild/RPMS/x86_64/libpdfium-devel-0.0.3989-1.el7.x86_64.rpm


    설치 후 , 앞에서 만든 테스트 프로그램을 빌드하고 실행해 본다.

    PDFIUM_REPO= /usr/include/pdfium/

    INC_DIR= -I ${PDFIUM_REPO}/public

    LIB_DIR= -L /lib64


    실행이 정상 동작하고 있다. 


    이제 gdal 과 링크하기 위한 삽질을 시작하기 위한 준비를 마쳤다.





    'Linux' 카테고리의 다른 글

    PDFium 라이브러리 삽질기 - 5  (0) 2019.12.16
    PDFium 라이브러리 삽질기 - 4  (0) 2019.12.13
    PDFium 라이브러리 삽질기 - 2  (0) 2019.12.10
    PDFium 라이브러리 삽질기 - 1  (0) 2019.12.10
    TmaxOS 3.9.1 x64 설치기  (0) 2019.08.20

    댓글

Designed by Tistory.