How I fix cups-printing in Buildroot

    image


    Intro


    Like I said earlier in previos articles, Buildroot is a great system for embedded Linux development. But sometimes strange things can happen.


    Once upon a workday, I got the following task: add printing system in firmware (Kraftway terminal Linux next generation). Ok, so I had to add cups + cups filter and to build firmware. I set a postscript-printer and got an error "Filter failed". Trivial tasks turned into serious work.


    In this article, I wrote my own way of solving this problem. It may be useful for other developers and IT-specialist and, also, for a deeper understanding of the Buildroot.


    If you are a Buildroot beginner, I recommend reading my previous articles.


    Update 1 may 2020


    Revisioned versions of this patches applied to master.


    Understanding of the printing system in Linux


    First of all, CUPS is not an ALL-IN-ONE printing solution. Below, I wrote a simple printing schema:


    • application sends user file (pdf,txt,jpeg, other) to CUPS
    • CUPS transforms user file to internal PDF (via QPDF)
    • CUPS selects needed filters and sends PDF to them
    • filters transform PDF to printer format:
      • ghostscript uses freetype for font rendering
      • gilters use image libs(libjpeg,libpng) for image rendering
    • filters send printer-ready data to backend
    • backend(lpd,smb,usb,etc) sends data to printer

    Ghostscript may be replaced with another render (like Poppler), but I use this schema. Filters depend on the printer manufacturer.The full printing system schema is more complex. But this one is simple enough to understand the article.


    Step one. Web interface


    "Ok", — said I, rolling up my sleeves.


    Buildroot has a 'target finalize' stage that cleans unnecessary files such as mans, docs, and others. Our target is bigger and more complex, so I'll show only the first 10 lines:


    alexey@comp:~/test/article/buildroot$ grep -n '.PHONY: target-finalize' -A 10 Makefile
    743:.PHONY: target-finalize
    744-target-finalize: $(PACKAGES) $(TARGET_DIR) host-finalize
    745-    @$(call MESSAGE,"Finalizing target directory")
    746-    $(call per-package-rsync,$(sort $(PACKAGES)),target,$(TARGET_DIR))
    747-    $(foreach hook,$(TARGET_FINALIZE_HOOKS),$($(hook))$(sep))
    748-    rm -rf $(TARGET_DIR)/usr/include $(TARGET_DIR)/usr/share/aclocal \
    749-        $(TARGET_DIR)/usr/lib/pkgconfig $(TARGET_DIR)/usr/share/pkgconfig \
    750-        $(TARGET_DIR)/usr/lib/cmake $(TARGET_DIR)/usr/share/cmake
    751-    find $(TARGET_DIR)/usr/{lib,share}/ -name '*.cmake' -print0 | xargs -0 rm -f
    752-    find $(TARGET_DIR)/lib/ $(TARGET_DIR)/usr/lib/ $(TARGET_DIR)/usr/libexec/ \
    753-        \( -name '*.a' -o -name '*.la' \) -print0 | xargs -0 rm -f

    CUPS has a special directory, which contains a web interface file. By default, the location of CUPS documents directory resides in /usr/share/doc, but this path is cleaned by Buildroot on the target-finalize stage, on image-build. I will use cups.css as a detector of the CUPS doc-dir path. This file is part of the CUPS web interface.


    Let's build the full system:


    alexey@comp:~/test/article/buildroot$ find output/ -iname cups.css
    output/host/x86_64-buildroot-linux-gnu/sysroot/usr/share/doc/cups/cups.css
    output/build/cups-2.3.1/doc/cups.css

    As you can see, no style.css is present in ${TARGET_DIR} because buildroot remove them:


    And some lines later:


    765: rm -rf $(TARGET_DIR)/usr/doc $(TARGET_DIR)/usr/share/doc

    Let's rebuild cups without image create (make cups-rebuild command):


    alexey@comp:~/test/article/buildroot$ find output/ -iname cups.css
    output/target/usr/share/doc/cups/cups.css
    output/host/x86_64-buildroot-linux-gnu/sysroot/usr/share/doc/cups/cups.css
    output/build/cups-2.3.1/doc/cups.css

    I wrote a short patch that moves this directory to /usr/share. This patch was applied to the Buildroot master(since 2020.02 version).


    Step two. QPDF — shadow warrior


    QPDF is used in CUPS for internal file converting, and it's a required dependence for cups. Using trace and cups error-log, I’ve founded a strange message:


    access ("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)

    I tested how it works and found a problem:


    $ file  /usr/share/cups/data/secret.pdf
    /usr/share/cups/data/secret.pdf: PDF document, version 1.2
    
    $ qpdf  /usr/share/cups/data/secret.pdf -
    open (): No such file or directory

    I tested this command on my desktop with Linux Mint and got a normal result:


    alexey@comp:~/Downloads$ file /usr/share/cups/data/secret.pdf
    /usr/share/cups/data/secret.pdf: PDF document, version 1.2
    alexey@comp:~/Downloads$ qpdf /usr/share/cups/data/secret.pdf - |head
    %PDF-1.2
    %����
    1 0 obj
    << /Pages 3 0 R /Type /Catalog >>
    endobj
    2 0 obj
    << /CreationDate (D:20140612184736+02'00') /ModDate (D:20140612184736+02'00') /Producer (GPL Ghostscript 9.14) >>
    endobj
    3 0 obj
    << /Count 1 /Kids [ 4 0 R ] /Type /Pages >>

    So looks like the problem is in QPDF build. I've studied the package file (package/QPDF/QPDF.mk) and found strange option '--without-random'


    alexey@comp:~/test/article/buildroot$ head -n 15 package/QPDF/QPDF.mk
    ################################################################################
    #
    # QPDF
    #
    ################################################################################
    
    QPDF_VERSION = 9.1.1
    QPDF_SITE = http://downloads.sourceforge.net/project/qpdf/qpdf/$(QPDF_VERSION)
    QPDF_INSTALL_STAGING = YES
    QPDF_LICENSE = Apache-2.0 or Artistic-2.0
    QPDF_LICENSE_FILES = LICENSE.txt Artistic-2.0
    QPDF_DEPENDENCIES = host-pkgconf zlib jpeg
    
    QPDF_CONF_OPTS = --without-random
    

    Next, I checked the available conf option:


    alexey@comp:~/test/article/buildroot$ ./output/build/qpdf-9.1.1/configure --help |grep random
      --enable-insecure-random
                              whether to use stdlib's random number generator
      --enable-os-secure-random
                              whether to try to use OS-provided secure random
      --with-random=FILE      Use FILE as random number seed [auto-detected]
    

    While I didn't find these options, I found another one "--with-random=". After that, I wrote a simple patch, rebuilt QPDF and got proper qpd work. This patch replaces "with-random" option with "--with-random=/dev/urandom"
    So, minus one problem on my way.


    Step three. Cups-filters and Ghostscript


    CUPS-filters are needed to transform CUPS internal representation to printer-ready format. They depend on the printer model. But CUPS-FILTER (early known as foomatic) is a good collection of different printer filters, especially for a generic-like printer (generic-pdf, generic-postscript, and other).


    These are the important strings in the cups-filters readme:


    For compiling and using this package CUPS, libqpdf (8.3.0 or newer), libjpeg, libpng, libtiff, freetype, font-tconfig, liblcms (liblcms2 recommended), libavahi-common, libavahi-client, libdbus, and glib are needed. It is highly recommended, especially if non-PDF printers are used, to have at least one of Ghostscript, Poppler, or MuPDF.

    OK, I chose Ghostscript:


    Ghostscript has better color management and is generally optimized more for printing.

    Now, let's look at the cups-filters package file (package/cups-filters/cups-filters.mk):


    head -n 21 package/cups-filters/cups-filters.mk
    ################################################################################
    #
    # cups-filters
    #
    ################################################################################
    
    CUPS_FILTERS_VERSION = 1.26.0
    CUPS_FILTERS_SITE = http://openprinting.org/download/cups-filters
    CUPS_FILTERS_LICENSE = GPL-2.0, GPL-2.0+, GPL-3.0, GPL-3.0+, LGPL-2, LGPL-2.1+, MIT, BSD-4-Clause
    CUPS_FILTERS_LICENSE_FILES = COPYING
    
    CUPS_FILTERS_DEPENDENCIES = cups libglib2 lcms2 qpdf fontconfig freetype jpeg
    
    CUPS_FILTERS_CONF_OPTS = --disable-imagefilters \
        --disable-mutool \
        --disable-foomatic \
        --disable-braille \
        --with-cups-config=$(STAGING_DIR)/usr/bin/cups-config \
        --with-sysroot=$(STAGING_DIR) \
        --with-pdftops=pdftops \
        --with-jpeg

    First, I add selected Ghostscript support by adding "--with-pdftops"; select depends on Ghostscript: if enabled — add the dependency for the current build:


    ifeq ($(BR2_PACKAGE_GHOSTSCRIPT),y)
    CUPS_FILTERS_CONF_OPTS += --with-pdftops=gs
    CUPS_FILTERS_DEPENDENCIES += ghostscript
    else
    CUPS_FILTERS_CONF_OPTS += --with-pdftops=pdftops
    endif

    Also, I added image printing (such as jpeg) support by removing " --disable-imagefilters" from config options. After that, cups-filters began to use Ghostscript as the default render.


    This patch is submitted, but I don't have any response, and it's not applied to buildroot.


    Step four. Ghostscript + CUPS = love


    In reality, this step parallels with step 4. And it's the hardest work in this task.


    alexey@comp:~/test/article/buildroot$ grep cups  package/ghostscript/ghostscript.mk
        --disable-cups \

    Ghostscript is built without cups-support! I thought it's a mistake, but it's true! I added cups support:


    ifeq ($(BR2_PACKAGE_CUPS),y)
    GHOSTSCRIPT_DEPENDENCIES += cups
    GHOSTSCRIPT_PRE_CONFIGURE_HOOKS += GHOSTSCRIPT_CUPS_CONFIG_FIX
    GHOSTSCRIPT_CONF_OPTS += --enable-cups
    else
    GHOSTSCRIPT_CONF_OPTS += --disable-cups
    endif

    Easy, but it doesn't help:


    gs --help| grep -i cups
    /usr/share/cups/fonts : /usr/share/ghostscript/fonts :

    And I didn’t see the cup device support. But on my Mint:


    alexey@comp:~/test/article/buildroot$ gs --help |grep -i cups
       chp2200 cif cljet5 cljet5c cljet5pr coslw2p coslwxl cups declj250 deskjet
       /usr/share/cups/fonts : /usr/share/ghostscript/fonts :

    I read Ghostscript build config and found that configure does not find cups. I opened Ghostscript configure.ac file and found something interesting:


    # this is an unpleasant hack
    # but if we are cross compiling, and there isn't a matching
    # pkconfig for the --host setting, then don't use the 'local'
    # pkconfig at all
    if test x"$cross_compiling" = x"yes"; then
      AC_PATH_PROG(BUILD_PKGCONFIG, pkg-config)
      if test x"$BUILD_PKGCONFIG" = x"$PKGCONFIG" ; then
        PKGCONFIG=
      fi
    fi

    It seems that the author of the Ghostscript check used cross-compile. Buildroot uses cross-compile, but it uses its own PATH and other environments to prevent using build-machine utils inside of toolchain. And this hack does not work properly. Also, an equivalent hack is used for cups-config and strip_xe:


    AC_PATH_TOOL(CUPSCONFIG,cups-config)
            if test x"$cross\_compiling" = x"yes"; then
                    AC_PATH_PROG(BUILD_CUPSCONFIG, cups-config)
                    if test x"$BUILD_CUPSCONFIG" = x"$CUPSCONFIG" ; then
                            CUPSCONFIG=
                    fi
                  fi

    I wrote a patch to remove this hack, and pkg-config started to work fine. [Full patch is submitted (http://lists.busybox.net/pipermail/buildroot/2020-May/281749.html), but I have no response, and it's not applied. Also, copy cups-config to $(HOST_DIR)/usr/bin/ because pkg-config search in this dir.


    Proper pkg-config's work resolves the problem with Freetype. Freetype is the default font render for Ghostscript. Without it, cups won't print normal text page — only blank space instead of text and images.


    Instead of conclusion


    Of course, I lost a lot of time before I found all these problems and fixed them. Yes, I understand that Buildroot, QPDF, cups, Ghostscript are opensource software, and I want to say "Thank you" to their developers and maintainers.


    I hope that the Buildroot-community will apply all of my patches. If not, everyone can read this article and get patches from the Buildroot mailing lists.

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 0

    Only users with full accounts can post comments. Log in, please.