Building and Installing QPDF — QPDF 11.9.0 documentation (2024)

This chapter describes how to build and install qpdf.

Dependencies

qpdf has few external dependencies. This section describes what youneed to build qpdf in various circ*mstances.

Basic Dependencies

  • A C++ compiler that supports C++-17

  • CMake version 3.16 or later

  • zlib or a compatible zlib implementation

  • A libjpeg-compatible library such as jpeg orlibjpeg-turbo

  • Recommended but not required: gnutlsto be able to use the gnutls crypto provider and/or openssl to be able to use the openssl cryptoprovider

The qpdf source tree includes a few automatically generated files. Thecode generator uses Python 3. Automatic code generation is off bydefault. For a discussion, refer to Build Options.

Test Dependencies

qpdf’s test suite is run by ctest, which is part of CMake, butthe tests themselves are implemented using an embedded copy of qtest, which is implemented in perl. OnWindows, MSYS2’s perl is known to work.

qtest requires GNU diffutils or any other diff thatsupports diff -u. The default diff command works onGNU/Linux and MacOS.

Part of qpdf’s test suite does comparisons of the contents PDF filesby converting them to images and comparing the images. The imagecomparison tests are disabled by default. Those tests are not requiredfor determining correctness of a qpdf build since the test suite alsocontains expected output files that are compared literally. The imagecomparison tests provide an extra check to make sure that any contenttransformations don’t break the rendering of pages. Transformationsthat affect the content streams themselves are off by default and areonly provided to help developers look into the contents of PDF files.If you are making deep changes to the library that cause changes inthe contents of the files that qpdf generates, then you should enablethe image comparison tests. Enable them by setting theQPDF_TEST_COMPARE_IMAGES environment variable to 1 beforerunning tests. Image comparison tests add these additionalrequirements:

Note: prior to qpdf 11, image comparison tests were enabled withinqpdf.test, and you had to disable them by settingQPDF_SKIP_TEST_COMPARE_IMAGES to 1. This was doneautomatically by ./configure. Now you have to enable imagecomparison tests by setting an environment variable. This change wasmade because developers have to set the environment variablethemselves now rather than setting it through the build. Either way,they are off by default.

Additional Requirements on Windows

  • To build qpdf with Visual Studio, there are no additionalrequirements when the default cmake options are used. You can buildqpdf from a Visual C++ command-line shell.

  • To build with mingw, MSYS2 is recommended with the mingw32 and/ormingw64 tool chains. You can also build with MSVC from an MSYS2environment.

  • qpdf’s test suite can run within the MSYS2 environment for bothmingw and MSVC-based builds.

For additional notes, see README-windows.md in the sourcedistribution.

Requirements for Building Documentation

The qpdf manual is written in reStructured Text and built with Sphinx using the Read the Docs Sphinx Theme. Versions of sphinx priorto version 4.3.2 probably won’t work. Sphinx requires Python 3. Inorder to build the HTML documentation from source, you need to installsphinx and the theme, which you can typically do with pip installsphinx sphinx_rtd_theme. To build the PDF version of thedocumentation, you need pdflatex, latexmk, and a fairlycomplete LaTeX installation. Detailed requirements can be found in theSphinx documentation. To see how the documentation is built for theqpdf distribution, refer to the build-scripts/build-doc filein the qpdf source distribution.

Build Instructions

Starting with qpdf 11, qpdf is built with CMake.

Basic Build Invocation

qpdf uses cmake in an ordinary way, so refer to the CMakedocumentation for details about how to run cmake. Here is abrief summary.

You can usually just run

cmake -S . -B buildcmake --build build

If you are using a multi-configuration generator such as MSVC, youshould pass --config <Config> (where <Config> is Release,Debug, RelWithDebInfo, or MinSizeRel as discussed in theCMake documentation) to the build command. If you are running asingle configuration generator such as the default Makefile generatorsin Linux or MSYS, you may want to pass -DCMAKE_BUILD_TYPE=<Config>to the original cmake command.

Run ctest to run the test suite. Since the real tests areimplemented with qtest, you willwant to pass --verbose to cmake so you can see the individualtest outputs. Otherwise, you will see a small number of ctestcommands that take a very long to run. If you want to run only aspecific test file in a specific test suite, you can set the TESTSenvironment variable (used by qtest-driver) and pass the -Rparameter to ctest. For example:

TESTS=qutil ctest --verbose -R libtests

would run only qutil.test from the libtests test suite.

Installation and Packaging

Installation can be performed using cmake --install or cpack.For most normal use cases, cmake --install or cpack can be runin the normal way as described in CMake documentation. qpdf followsall normal installation conventions and uses CMake-defined variablesfor standard behavior.

There are several components that can be installed separately:

Installation Components

cli

Command-line tools

lib

The runtime libraries; required if you built with sharedlibraries

dev

Static libraries, header files, and other files needed bydevelopers

doc

Documentation and, if selected for installation, the manual

examples

Example source files

Note that the lib component installs only runtime libraries, notheader files or other files/links needed to build against qpdf. Forthat, you need dev. If you are using shared libraries, the devwill install files or create symbolic links that depend on filesinstalled by lib, so you will need to install both. If you wantedto build software against the qpdf library and only wanted to installthe files you needed for that purpose, here are some examples:

  • Install development files with static libraries only:

    cmake -S . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_SHARED_LIBS=OFFcmake --build build --parallel --target libqpdfcmake --install build --component dev
  • Install development files with shared libraries only:

    cmake -S . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_STATIC_LIBS=OFFcmake --build build --parallel --target libqpdfcmake --install build --component libcmake --install build --component dev
  • Install development files with shared and static libraries:

    cmake -S . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfocmake --build build --parallel --target libqpdf libqpdf_staticcmake --install build --component libcmake --install build --component dev

There are also separate options, discussed in Build Options,that control how certain specific parts of the software are installed.

Build Options

All available build options are defined in the the top-levelCMakeLists.txt file and have help text. You can see them usingany standard cmake front-end (like cmake-gui or ccmake). Thissection describes options that apply to most users. If you are tryingto map autoconf options (from prior to qpdf 11) to cmake options,please see Converting From autoconf to cmake.

If you are packaging qpdf for a distribution, you should also readNotes for Packagers.

Basic Build Options

BUILD_DOC

Whether to build documentation with sphinx. You must have therequired tools installed.

BUILD_DOC_HTML

Visible when BUILD_DOC is selected. This option controls buildingHTML documentation separately from PDF documentation sincethe sphinx theme is only needed for the HTML documentation.

BUILD_DOC_PDF

Visible when BUILD_DOC is selected. This option controls buildingPDF documentation separately from HTML documentation sinceadditional tools are required to build the PDF documentation.

BUILD_SHARED_LIBS, BUILD_STATIC_LIBS

You can configure whether to build shared libraries, staticlibraries, or both. You must select at least one of these options.For rapid iteration, select only one as this cuts the build time inhalf.

On Windows, if you build with shared libraries, you must have theoutput directory for libqpdf (e.g. libqpdf/Release orlibqpdf within the build directory) in your path so that thecompiled executables can find the DLL. Updating your path is notnecessary if you build with static libraries only.

FUTURE

This option enables changes planned for the next major release to beincluded. They are NOT part of the stable API. These changes are ABIbreaking and are subject to change, which means code linked againsta qpdf built with this option may not be binary compatible withinstalled qpdf libraries. Set this if you want to test your codewith proposed QPDF API changes and provide feedback prior to theinclusion of those changes in a release. Packagers should neverdistribute packages built with this option.

QTEST_COLOR

Turn this on or off to control whether qtest uses color in itsoutput.

Options for Working on qpdf

CHECK_SIZES

The source file qpdf/sizes.cc is used to display the sizesof all objects in the public API. Consistency of its output betweenreleases is used as part of the check against accidental breakage ofthe binary interface (ABI). Turning this on causes a test to be runthat ensures an exact match between classes in sizes.cc andclasses in the library’s public API. This option requires Python 3.

ENABLE_COVERAGE

Compile with --coverage. See README-maintainer.md forinformation about generating coverage reports.

ENABLE_QTC

This is off by default, except in maintainer mode. When off,QTC::TC calls are compiled out by having QTC::TC be an emptyinline function. The underlying QTC::TC remains in the library,so it is possible to build and package the qpdf library withENABLE_QTC turned off while still allowing developer code to useQTC::TC if desired. If you are modifying qpdf code, it’s a goodidea to have this on for more robust automated testing. Otherwise,there’s no reason to have it on.

GENERATE_AUTO_JOB

Some qpdf source files are automatically generated fromjob.yml and the CLI documentation. If you are adding newcommand-line arguments to the qpdf CLI or updatingmanual/cli.rst in the qpdf sources, you should turn this on.This option requires Python 3.

WERROR

Make any compiler warnings into errors. We want qpdf to compile freeof warnings whenever possible, but there’s always a chance that acompiler upgrade or tool change may cause warnings to appear thatweren’t there before. If you are testing qpdf with a new compiler,you should turn this on.

Environment-Specific Options

SHOW_FAILED_TEST_OUTPUT

Ordinarily, qtest (which drives qpdf’s test suite) writes detailedinformation about its output to the file qtest.log in the buildoutput directory. If you are running a build in a continuousintegration or automated environment where you can’t get to thosefiles, you should enable this option and also run ctest--verbose or ctest --output-on-failure. This will causedetailed test failure output to be written into the build log.

CI_MODE

Turning this on sets options used in qpdf’s continuous integrationenvironment to ensure we catch as many problems as possible.Specifically, this option enables SHOW_FAILED_TEST_OUTPUT andWERROR and forces the native crypto provider to be built.

MAINTAINER_MODE

Turning this option on sets options that should be on if you aremaintaining qpdf. In turns on the following:

  • BUILD_DOC

  • CHECK_SIZES

  • ENABLE_QTC

  • GENERATE_AUTO_JOB

  • WERROR

  • REQUIRE_NATIVE_CRYPTO

It is possible to turn BUILD_DOC off in maintainer mode so thatthe extra requirements for building documentation don’t have to beavailable.

Build-time Crypto Selection

Since version 9.1.0, qpdf can use external crypto providers inaddition to its native provider. For a general discussion, seeCrypto Providers. This section discusses how to configure which cryptoproviders are compiled into qpdf.

In nearly all cases, external crypto providers should be preferredover the native one. However, if you are not concerned about workingwith encrypted files and want to reduce the number of dependencies,the native crypto provider is fully supported.

By default, qpdf’s build enables every external crypto providers whosedependencies are available and only enables the native crypto providerif no external providers are available. You can change this behaviorwith the options described here.

USE_IMPLICIT_CRYPTO

This is on by default. If turned off, only explicitly selectedcrypto providers will be built. You must use at least one of theREQUIRE options below.

ALLOW_CRYPTO_NATIVE

This option is only available when USE_IMPLICIT_CRYPTO is selected,in which case it is on by default. Turning it off prevents qpdf fromfalling back to the native crypto provider when no external provideris available.

REQUIRE_CRYPTO_NATIVE

Build the native crypto provider even if other options areavailable.

REQUIRE_CRYPTO_GNUTLS

Require the gnutls crypto provider. Turning this on makes in anerror if the gnutls library is not available.

REQUIRE_CRYPTO_OPENSSL

Require the openssl crypto provider. Turning this on makes in anerror if the openssl library is not available.

DEFAULT_CRYPTO

Explicitly select which crypto provider is used by default. SeeRuntime Crypto Provider Selection for information about run-time selection ofthe crypto provider. If not specified, qpdf will pick gnutls ifavailable, otherwise openssl if available, and finally native as alast priority.

Example: if you wanted to build with only the gnutls crypto provider,you should run cmake with -DUSE_IMPLICIT_CRYPTO=0-DREQUIRE_CRYPTO_GNUTLS=1.

Advanced Build Options

These options are used only for special purposes and are not relevantto most users.

AVOID_WINDOWS_HANDLE

Disable use of the HANDLE type in Windows. This can be useful ifyou are building for certain embedded Windows environments. Somefunctionality won’t work, but you can still process PDF files frommemory in this configuration.

BUILD_DOC_DIST, INSTALL_MANUAL

By default, installing qpdf does not include a pre-built copy of themanual. Instead, it installs a README file that tells people whereto find the manual online. If you want to install the manual, youmust enable the INSTALL_MANUAL option, and you must have adoc-dist directory in the manual directory of the build. Thedoc-dist directory is created if BUILD_DOC_DIST is selectedand BUILD_DOC_PDF and BUILD_DOC_HTML are both on.

The BUILD_DOC_DIST and INSTALL_MANUAL options are separateand independent because of the additional tools required to builddocumentation. In particular, for qpdf’s official releasepreparation, a doc-dist directory is built in Linux and thenextracted into the Windows builds so that it can be included in theWindows installers. This prevents us from having to build thedocumentation in a Windows environment. For additional discussion,see Documentation Packaging Rationale.

INSTALL_CMAKE_PACKAGE

Controls whether or not to install qpdf’s cmake configuration file(on by default).

INSTALL_EXAMPLES

Controls whether or not to install qpdf’s example source files withdocumentation (on by default).

INSTALL_PKGCONFIG

Controls whether or not to install qpdf’s pkg-config configurationfile (on by default).

OSS_FUZZ

Turning this option on changes the build of the fuzzers in a mannerspecifically required by Google’s oss-fuzz project. There is noreason to turn this on for any other reason. It is enabled by thebuild script that builds qpdf from that context.

SKIP_OS_SECURE_RANDOM, USE_INSECURE_RANDOM

The native crypto implementation uses the operating systems’s securerandom number source when available. It is not used when an externalcrypto provider is in use. If you are building in a very specializedenvironment where you are not using an external crypto provider butcan’t use the OS-provided secure random number generator, you canturn both of these options on. This will cause qpdf to fall back toan insecure random number generator, which may generate guessablerandom numbers. The resulting qpdf is still secure, but encryptedfiles may be more subject to brute force attacks. Unless you knowyou need these options for a specialized purpose, you don’t needthem. These options were added to qpdf in response to a specialrequest from a user who needed to run a specialized PDF-related taskin an embedded environment that didn’t have a secure random numbersource.

Building without wchar_t

It is possible to build qpdf on a system that doesn’t havewchar_t. The resulting build of qpdf is not API-compatible with aregular qpdf build, so this option cannot be selected from cmake. Thisoption was added to qpdf to support installation on a very strippeddown embedded environment that included only a partial implementationof the standard C++ library.

You can disable use of wchar_t in qpdf’s code by defining theQPDF_NO_WCHAR_T preprocessor symbol in your build (e.g. byincluding -DQPDF_NO_WCHAR_T in CFLAGS and CXXFLAGS).

While wchar_t is part of the C++ standard library and should bepresent on virtually every system, there are some stripped downsystems, such as those targeting certain embedded environments, thatlack wchar_t. Internally, qpdf uses UTF-8 encoding for everything,so there is nothing important in qpdf’s API that uses wchar_t.However, there are some helper methods for converting betweenwchar_t* and char*.

If you are building in an environment that does not supportwchar_t, you can define the preprocessor symbolQPDF_NO_WCHAR_T in your build. This will work whether you arebuilding qpdf and need to avoid compiling the code that uses wchar_tor whether you are building client code that uses qpdf.

Note that, when you build code with libqpdf, it is not necessary tohave the definition of QPDF_NO_WCHAR_T in your build match whatwas defined when the library was built as long as you are not callingany of the methods that use wchar_t.

Crypto Providers

Starting with qpdf 9.1.0, the qpdf library can be built with multipleimplementations of providers of cryptographic functions, which we referto as “crypto providers.” At the time of writing, a cryptoimplementation must provide MD5 and SHA2 (256, 384, and 512-bit) hashesand RC4 and AES256 with and without CBC encryption. In the future, ifdigital signature is added to qpdf, there may be additional requirementsbeyond this. Some of these are weak cryptographic algorithms. For adiscussion of why they’re needed, see Weak Cryptography.

The available crypto provider implementations are gnutls,openssl, and native. OpenSSL support was added in qpdf 10.0.0with support for OpenSSL added in 10.4.0. GnuTLS support wasintroduced in qpdf 9.1.0. Additional implementations can be added asneeded. It is also possible for a developer to provide their ownimplementation without modifying the qpdf library.

For information about selecting which crypto providers are compiledinto qpdf, see Build-time Crypto Selection.

Runtime Crypto Provider Selection

You can use the --show-crypto option to qpdf toget a list of available crypto providers. The default provider isalways listed first, and the rest are listed in lexical order. Eachcrypto provider is listed on a line by itself with no other text,enabling the output of this command to be used easily in scripts.

You can override which crypto provider is used by setting theQPDF_CRYPTO_PROVIDER environment variable. There are few reasonsto ever do this, but you might want to do it if you were explicitlytrying to compare behavior of two different crypto providers whiletesting performance or reproducing a bug. It could also be useful forpeople who are implementing their own crypto providers.

Crypto Provider Information for Developers

If you are writing code that uses libqpdf and you want to force acertain crypto provider to be used, you can call the methodQPDFCryptoProvider::setDefaultProvider. The argument is the nameof a built-in or developer-supplied provider. To add your own cryptoprovider, you have to create a class derived from QPDFCryptoImpland register it with QPDFCryptoProvider. For additionalinformation, see comments in include/qpdf/QPDFCryptoImpl.hh.

Crypto Provider Design Notes

This section describes a few bits of rationale for why the cryptoprovider interface was set up the way it was. You don’t need to know anyof this information, but it’s provided for the record and in case it’sinteresting.

As a general rule, I want to avoid as much as possible including largeblocks of code that are conditionally compiled such that, in mostbuilds, some code is never built. This is dangerous because it makes itvery easy for invalid code to creep in unnoticed. As such, I want it tobe possible to build qpdf with all available crypto providers, and thisis the way I build qpdf for local development. At the same time, if aparticular packager feels that it is a security liability for qpdf touse crypto functionality from other than a library that getsconsiderable scrutiny for this specific purpose (such as gnutls,openssl, or nettle), then I want to give that packager the ability tocompletely disable qpdf’s native implementation. Or if someone wants toavoid adding a dependency on one of the external crypto providers, Idon’t want the availability of the provider to impose additionalexternal dependencies within that environment. Both of these aresituations that I know to be true for some users of qpdf.

I want registration and selection of crypto providers to be thread-safe,and I want it to work deterministically for a developer to provide theirown crypto provider and be able to set it up as the default. This wasthe primary motivation behind requiring C++-11 as doing so enabled me toexploit the guaranteed thread safety of local block staticinitialization. The QPDFCryptoProvider class uses a singletonpattern with thread-safe initialization to create the singleton instanceof QPDFCryptoProvider and exposes only static methods in its publicinterface. In this way, if a developer wants to call anyQPDFCryptoProvider methods, the library guarantees theQPDFCryptoProvider is fully initialized and all built-in cryptoproviders are registered. Making QPDFCryptoProvider actually knowabout all the built-in providers may seem a bit sad at first, but thischoice makes it extremely clear exactly what the initialization behavioris. There’s no question about provider implementations automaticallyregistering themselves in a nondeterministic order. It also means thatimplementations do not need to know anything about the providerinterface, which makes them easier to test in isolation. Anotheradvantage of this approach is that a developer who wants to developtheir own crypto provider can do so in complete isolation from the qpdflibrary and, with just two calls, can make qpdf use their provider intheir application. If they decided to contribute their code, plugging itinto the qpdf library would require a very small change to qpdf’s sourcecode.

The decision to make the crypto provider selectable at runtime was one Istruggled with a little, but I decided to do it for various reasons.Allowing an end user to switch crypto providers easily could be veryuseful for reproducing a potential bug. If a user reports a bug thatsome cryptographic thing is broken, I can easily ask that person to trywith the QPDF_CRYPTO_PROVIDER variable set to different values. Thesame could apply in the event of a performance problem. This also makesit easier for qpdf’s own test suite to exercise code with differentproviders without having to make every program that links with qpdfaware of the possibility of multiple providers. In qpdf’s continuousintegration environment, the entire test suite is run for each supportedcrypto provider. This is made simple by being able to select theprovider using an environment variable.

Finally, making crypto providers selectable in this way establish apattern that I may follow again in the future for stream filterproviders. One could imagine a future enhancement where someone couldprovide their own implementations for basic filters like/FlateDecode or for other filters that qpdf doesn’t support.Implementing the registration functions and internal storage ofregistered providers was also easier using C++-11’s functionalinterfaces, which was another reason to require C++-11 at this time.

Converting From autoconf to cmake

Versions of qpdf before qpdf 11 were built with autoconf and ahome-grown GNU Make-based build system. If you built qpdf with special./configure options, this section can help you switch them over tocmake.

In most cases, there is a one-to-one mapping between configure optionsand cmake options. There are a few exceptions:

  • The cmake build behaves differently with respect to whether or notto include support for the native crypto provider. Specifically, itis not implicitly enabled unless explicitly requested if there areother options available. You can force it to be included by enablingREQUIRE_CRYPTO_NATIVE. For details, see Build-time Crypto Selection.

  • The --enable-external-libs option is no longer available. Thecmake build detects the presence of external-libs automatically.See README-windows.md in the source distribution for a morein-depth discussion.

  • The sense of the option representing use of the OS-provided securerandom number generator has been reversed: the--enable-os-secure-random, which was on by default, has beenreplaced by the SKIP_OS_SECURE_RANDOM option, which is off bydefault. The option’s new name and behavior match the preprocessorsymbol that it turns on.

  • Non-default test configuration is selected with environmentvariables rather than cmake. The old ./configure options justset environment variables. Note that the sense of the variable forimage comparison tests has been reversed. It used to be that you hadto set QPDF_SKIP_TEST_COMPARE_IMAGES to 1 to disable imagecomparison tests. This was done by default. Now you have to setQPDF_TEST_COMPARE_IMAGES to 1 to enable image comparisontests. Either way, they are off by default.

  • Non-user-visible change: the preprocessor symbol that triggers theexport of functions into the public ABI (application binaryinterface) has been changed from DLL_EXPORT tolibqpdf_EXPORTS. This detail is encapsulated in the build and isonly relevant to people who are building qpdf on their own or whomay have previously needed to work around a collision between qpdf’suse of DLL_EXPORT and someone else’s use of the same symbol.

  • A handful of options that were specific to autoconf or the old buildsystem have been dropped.

  • cmake --install installs example source code indoc/qpdf/examples in the examples installation component.Packagers are encouraged to package this with development files ifthere is no separate doc package. This can be turned off bydisabling the INSTALL_EXAMPLES build option.

There are some new options available in the cmake build that were notavailable in the autoconf build. This table shows the old options andtheir equivalents in cmake.

configure flags to cmake options

enable-avoid-windows-handle

AVOID_WINDOWS_HANDLE

enable-check-autofiles

none – not relevant to cmake

enable-crypto-gnutls

REQUIRE_CRYPTO_GNUTLS

enable-crypto-native

REQUIRE_CRYPTO_NATIVE (but see above)

enable-crypto-openssl

REQUIRE_CRYPTO_OPENSSL

enable-doc-maintenance

BUILD_DOC

enable-external-libs

none – detected automatically

enable-html-doc

BUILD_DOC_HTML

enable-implicit-crypto

USE_IMPLICIT_CRYPTO

enable-insecure-random

USE_INSECURE_RANDOM

enable-ld-version-script

none – detected automatically

enable-maintainer-mode

MAINTAINER_MODE (slight differences)

enable-os-secure-random (on by default)

SKIP_OS_SECURE_RANDOM (off by default)

enable-oss-fuzz

OSS_FUZZ

enable-pdf-doc

BUILD_DOC_PDF

enable-rpath

none – cmake handles rpath correctly

enable-show-failed-test-output

SHOW_FAILED_TEST_OUTPUT

enable-test-compare-images

set the QPDF_TEST_COMPARE_IMAGES environment variable

enable-werror

WERROR

with-buildrules

none – not relevant to cmake

with-default-crypto

DEFAULT_CRYPTO

large-file-test-path

set the QPDF_LARGE_FILE_TEST_PATH environment variable

Building and Installing QPDF — QPDF 11.9.0 documentation (2024)
Top Articles
Latest Posts
Article information

Author: Terrell Hackett

Last Updated:

Views: 6534

Rating: 4.1 / 5 (52 voted)

Reviews: 83% of readers found this page helpful

Author information

Name: Terrell Hackett

Birthday: 1992-03-17

Address: Suite 453 459 Gibson Squares, East Adriane, AK 71925-5692

Phone: +21811810803470

Job: Chief Representative

Hobby: Board games, Rock climbing, Ghost hunting, Origami, Kabaddi, Mushroom hunting, Gaming

Introduction: My name is Terrell Hackett, I am a gleaming, brainy, courageous, helpful, healthy, cooperative, graceful person who loves writing and wants to share my knowledge and understanding with you.