Francesco Rizzi
Francesco Rizzi

Reputation: 631

C++ | Compiling LOG4CXX AND APR

I would like to use external libraries in my project. For example the apache log4cxx. I'm compiling for windows.

I know i have to compile first:

  1. Apache APR
  2. Apache APR-util
  3. Apache iconv.

I saw only these three dependencies on the main page.

I'm using MinGW-64 as compiler and CodeBlocks as IDE. Simply importing in my project all the files of each dependency does not work.

For example: if i add ALL the files of Apache APR i get "File not found error":

Error #1

If I try to do the same with the other libraries other errors occur.

I'm sure i am not understanding how to build external libraries by using their source code.

UPDATE I installed Visual studio, now i'm trying to compile the libraries but (obviosly...) compiler returns errors (error code C2513): Error

Folder structure is the following: Error3

Upvotes: 1

Views: 1770

Answers (3)

user8556182
user8556182

Reputation: 1

The problem for:

APR_DECLARE_LATE_DLL_FUNC(DLL_IPHLPAPI, PCHAR, NETIOAPI_API_, if_indextoname, 0, (

is not APR_DECLARE_LATE_DLL_FUNC but NETIOAPI_API_ or netioapi.h cannot be seen at that point.

I used CMake to generate Windows7 build and converted all to VS2019 then 2022. I am using apr/lib for build and see I have an apr.h in apr/lib but apr/lib/apr.h and apr/include/apr.h are different - apr/include/apr.h:

#define _WIN32_WINNT 0x0501

while the lib/apr.h has:

#define _WIN32_WINNT 0x0601

if you build apr/lib/APR.sln's project one by one, not the whole solution (so that include/apr.h is not generated), you will be able to build all okay, if include/apr.h is not present. My project has ../lib in its include directory, meaning it was using apr/lib/apr.h. This lead me to conclude that 0x0501 in the generated header is a problem. So I fixed the generated include/apr.h, or precisely fixed include/apr.h.in (not affecting apr.h) and apr.hw (affecting apr.h) by replacing 0x0501 with 0x0601, that issue was solved.

I still have other issues in apr-util/iconv build, not having enough time to look at that yet.

Upvotes: 0

rm5248
rm5248

Reputation: 2635

There are several options for how to build log4cxx, depending on your setup. The current way is to use the provided cmake files in order to build it.

The only dependencies requires are APR and APR-util(which depends on either expat or libxml).

Option 1: vcpkg

If you're on Windows and using CMake to build your project, the easiest way is to simply install vcpkg and use the recipe that is already included in vcpkg. This can be done simply as follows:

git clone https://github.com/microsoft/vcpkg
.\bootstrap-vcpkg.bat
.\vcpkg install log4cxx

This will download log4cxx and all of the dependencies required(APR, APR-util, expat, etc). From there, you can then use the generated CMake toolchains file that vcpkg creates(see the vcpkg documentation for more information)

Option 2: Build all dependencies separately

All of the required dependencies can be built with CMake. When you install and configure the dependencies, the best way is to make sure that they are all installed in the same root folder on your system(e.g. the installation directory is set to the same for all dependencies). This makes it easier to configure the build systems.

See this JIRA issue for some more information and some clues as to how to build separately.

Upvotes: 0

HolyBlackCat
HolyBlackCat

Reputation: 96166

Preface

  • Instead of giving you the answer right away, I'll first explain my thought process.

  • I'll only go through one of the libraries, but repeating the same thing for other ones should be easy.

  • Since I'm not on Windows, I can't use MSYS2 itself and will have to use its bastard child (which I'm the author of). So there may be minor inaccuracies in the instructions.

Installing MSYS2

MSYS2 is a way to get GCC on Windows. In addition to the compiler, in its package manager it provides some prebuilt libraries, and ports of command-line utilities such as bash or make (which are available on Linux out of the box, but normally don't work on Windows).

First, uninstall any versions on MinGW/GCC you might currently have. After you install GCC from MSYS2, you can tell CodeBlocks to use it instead of whatever it uses now.

Download and install MSYS2 from here. You don't want the installation path to contain spaces or any weird symbols.

Start it, you should see a terminal.

-- Updating MSYS2 --

MSYS2 should be updated after its installed. To update, run pacman -Syuu.

It might warn you that it will close itself to finish the update. If it happens, restart it and run the same command again the finish the update.

You might want to run this command from time to time to keep your installation up-to-date.

Now you can run pacman -Ss SomeText to search for packages and pacman -S PackageNames to install packages.

-- Three sides of MSYS2 --

MSYS2 can be started in three different modes, the current mode is shown in the terminal in magenta letters.

One way to select modes is by using different exe files in the installation directory (mingw64.exe, and so on).

In the package manager, there are three sets of packages corresponding to those modes. It doesn't matter which mode is active when you install the packages, but it matters for actual compilation.

  • MINGW32 - for compiling 32-bit applications. Package names are prefixed with mingw-w64-i686-.
  • MINGW64 - for compiling 64-bit applications. Package names are prefixed with mingw-w64-x86_64-
  • MSYS - for compiling applications with POSIX emulation. Packages have no prefix.

Normally you don't want to use the last one. It's used to compile non-portable applications originally written for Linux-like systems, that don't work on Windows otherwise. Programs such as bash and make that come with MSYS2 were compiled with it.

Often you'll see three variants of a package, one for each mode. For example, if you do pacmake -Ss gcc (to search for "gcc" packages), you'll see mingw-w64-i686-gcc, mingw-w64-x86_64-gcc, and just gcc.

How do you select a package from the three? Here's the rule of thumb:

  • First, look for a prefixed package. (mingw-w64-x86_64-... if you're compiling for 64 bits, or mingw-w64-i686-... for 32 bits).

  • If there's no prefixed package, and you were looking for a compiler or a library, you're out of luck, there's no such package.

  • If you weren't looking for a compiler or a library, you can settle for an unprefixed package.

-- Installing tools --

With this knowledge, you're ready to install the tools from MSYS2 pacakge manager.

  • pacman -S mingw-w64-x86_64-gcc for GCC.

  • pacman -S mingw-w64-x86_64-gdb for GDB, the debugger. Might be useful.

  • pacman -S mingw-w64-x86_64-cmake make patch for some other tools. Hopefully I didn't forget anything.

    Note that make is the exception from the rule of thumb. There's another package called mingw-w64-x86_64-make, but long story short it's jank, and you want to use the unprefixed make instead.

    I used to have some problems with the CMake package. If it starts acting up, uninstall it and download the official CMake installer. If you use it, don't forget to add it to the PATH.

Compiling the library

I'm going to compile APR, the other libraries should be similar.

First, I search for it in the packages: pacman -Ss apr - the package is there. I tried to install it and compile a test program (it worked), so we know for sure it can be used on Windows.

But since you want to compile it yourself, we'll continue. If you decided to install the APR package to try it out, now is a good time to uninstall it, to avoid any interference.

Make sure MSYS2 is running in MINGW64 mode (look at the magenta text in the terminal). If it's not, restart it using mingw64.exe. When you were installing the packages, it didn't matter what mode was active, but now when you're compiling things it becomes important.

I'll first show my failed attempts first, to explain the thought process.

-- Failed attempt 1 --

I downloaded the APR source from here. There are separate downloads for Windows and Linux, I decided to go for apr-1.7.0-win32-src.zip.

Extracted the archive. Opened the resulting directory in the terminal (using cd, I hope you know what this is).

What exactly you do next depends on the files you see.

Since there's CMakeLists.txt, I tried building with CMake:

# Create an arbitrary directory
mkdir _build
cd _build
# Configure
cmake .. -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -G "MSYS Makefiles"
# Build (-j12 is optional, 12 is the number of CPU cores you want to use)
make -j12

On the last command I got cryptic errors. Let's try something else. I erased the _build and started looking for a different approach.

-- Failed attempt 2 --

I downloaded apr-1.7.0.tar.gz instead (the non-Windows variant of the sources). There's CMakeLists.txt, so I tried CMake again - nope, no luck.

I'm also seeing a configure file, so it's also possible to build with Autotools. (Normally it's either CMakeLists.txt or configure. If you see neither, then the build process is more exotic and should be explained in the readme.)

Let's try Autotools:

# Configure
./configure
# Build
make -j12

Got errors on first step, so we need a different approach.

-- Successful attempt --

Normally by this point you already succeed, but APR refuses to build out of the box. Yet MSYS2 folks managed to build it, how?

Let's figure out. Go to MSYS2 package sources, and look for APR.

Here we see several .patch files. They explain what modifications MSYS2 developers made to the APR source code to be able to build it. They are in a computer-readable format, and there's a program that applies them to the code automatically.

Download the .patch files, they will be useful later.

Now look at the PKGBUILD file. It contains computer-readable instructions on building APR. There is a way to execute them automatically, but I'll rather do it by hand for educational purposes.

I don't understand all of the PKGBUILD contents, but it's not necessary. You see following in it:

  • pkgver=1.6.5 They are using slightly outdated 1.6.5 instead of 1.7.0.

    I tried building 1.7.0 and failed, so get rid of 1.7.0 and download 1.6.5 from here.


  • makedepends=("${MINGW_PACKAGE_PREFIX}-gcc"
                 "${MINGW_PACKAGE_PREFIX}-libtool"
                 "${MINGW_PACKAGE_PREFIX}-python")
    
    To be able to build this package, they have installed gcc, libtool, and python. We already have GCC, now we just need the rest. Run:
    pacman -S mingw-w64-x86_64-libtool mingw-w64-x86_64-python
    

  • prepare() {
      cd "${srcdir}/${_realname}-${pkgver}"
    
      patch -p0 -i ${srcdir}/apr_ssize_t.patch
      patch -p0 -i ${srcdir}/apr_wtypes.patch
    
      ./buildconf
      # autoreconf -fi
    }
    
    This is how they "prepare" for the build. Lets do something similar. Copy the patch files to the apr-1.6.5 directory and run:
    patch -p0 -i apr_wtypes.patch
    patch -p0 -i apr_ssize_t.patch
    ./buildconf
    

  • build() {
      [[ -d build-${MINGW_CHOST} ]] && rm -rf build-${MINGW_CHOST}
      mkdir -p build-${MINGW_CHOST}
      cd build-${MINGW_CHOST}
    
      # Disable IPv6.
      ../${_realname}-${pkgver}/configure \
        --prefix="${MINGW_PREFIX}" \
        --build=${MINGW_CHOST} \
        --host=${MINGW_CHOST} \
        --target=${MINGW_CHOST} \
        --enable-static \
        --enable-shared \
        --includedir="${MINGW_PREFIX}/include/apr-1" \
        --with-installbuilddir="${MINGW_PREFIX}/share/apr-1/build" \
        --enable-nonportable-atomics \
        --with-devrandom=/dev/urandom \
        --disable-ipv6
    
      make
    }
    
    So they use configure and make like we tried to do, but with some extra flags. Let's not worry about the flags, just do:
    ./configure
    make -j12
    

And... it builds successfully!

Using the compiled library

You compiled the library, which created some files for you to use. What are they?

You need .a (static libraries) and .dll (dynamic libraries). Quick search shows they are in the .libs directory.

You also need the headers, which seem to be in the include directory. Everything else is no longer needed.

Now you need to know what compiler and linkers flags to use. Those can be found in a .pc file (apr.pc in this case) which for me looks like this:

prefix=/usr/local/apr
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
APR_MAJOR_VERSION=1
includedir=${prefix}/include/apr-${APR_MAJOR_VERSION}

Name: APR
Description: The Apache Portable Runtime library
Version: 1.6.5
Libs: -L${libdir} -lapr-${APR_MAJOR_VERSION} -lshell32 -ladvapi32 -lws2_32 -lrpcrt4 -lmswsock
Cflags: -DWIN32 -D__MSVCRT__ -D_LARGEFILE64_SOURCE -g -O2 -I${includedir}

Looking at the last two lines and ignoring some of the optional flags, we get this:

  • Compiler flags: -DWIN32 -D__MSVCRT__ -D_LARGEFILE64_SOURCE -Ipath/to/apr-1.6.5/include
  • Linker flags: -lapr-1 -lshell32 -ladvapi32 -lws2_32 -lrpcrt4 -lmswsock -Lpath/to-apr-1.6.5/.libs

Now we can try compiling a simple program from the terminal. Create a file called 1.cpp with following contents:

#include <iostream>
#include <apr_strings.h>

int main()
{
    char a[] = " Hello , world ! ";
    char b[sizeof a];
    apr_collapse_spaces(b, a);
    std::cout << b << '\n';
}

Build it using:

g++ 1.cpp -DWIN32 -D__MSVCRT__ -D_LARGEFILE64_SOURCE -Iapr-1.6.5/include -lapr-1 -lshell32 -ladvapi32 -lws2_32 -lrpcrt4 -lmswsock -Lapr-1.6.5/.libs

Since we're building from the terminal, our compiler and linker flags are in the same place. But when you'll be using CodeBlocks, you'll have to put them in two different places in the project settings.

In this command, you have to replace paths after -I and -L with the actual paths to your APR sources.

If the command runs successfully, you get your a.exe.

To run it, you first need to copy all .dlls from apr-1.6.5/.libs to the directory where the .exe is. Now you should be able to type ./a.exe and see it print Hello,world!.

CodeBlocks

If you want to do the same thing from CodeBlocks, you need to create a project, and in the project settings specify the same compiler and linker flags you used here.

Also, in CodeBlocks settings you'll have to specify the path to the GCC compiler you installed from MSYS2 (it should be in C:/msys64/mingw64/bin/).

Upvotes: 1

Related Questions