Hacking Threading Building Blocks into Cygwin, Part 2

My first blog post about Threading Building Blocks and Cygwin didn't include "Hacking" in the title -- but that's definitely what I'm doing at this point, so this and subsequent posts will be titled that way. If/when I reach the point where I know how to build and use TBB within the Cygwin environment, then I'll clean up all my code and write a final post that skips all the intervening experiments and missteps.

As I said near the end of my last post, one problem with using TBB within Unix-on-Windows environments is knowing where the dividing line between Unix and Windows actually lies. There are differences here between Cygwin, MinGW (Minimalist GNU for Windows), and UWIN. So, while a solution for all of these will involve something of a mixture of TBB build constructs, there will not be a single solution that works for all three environments.

The objective of my subsequent experiments with Cygwin was to have the TBB build process properly identify the Cygwin platform. To do this, I made changes to the following files in the TBB build directory:



    • Makefile.tbb - inserted the TBB20_INSTALL_DIR environment variable definition (for convenience)

    • common.inc - specified the tbb_os variable as cygwin



And I added the following new files:



    • cygwin.inc - adapted from linux.inc

    • cygwin.gcc.inc - adapted from linux.gcc.inc



That brought me to a certain point, but make still didn't get far. It turns out that Cygwin doesn't have a getconf command. This is used in linux.inc (my template for cygwin.inc) to identify the glibc version. I searched the Web for a solution, but could not find one. I noticed that UWIN has a getconf command which is actually a script; but I couldn't get the script to work under Cygwin, even after playing around a bit with the script parameters (for example, tweaking the typeset command parameters -- typeset in UWIN and Cygwin differ).

Next I tried to find a way to have Cygwin tell me what glibc version I have installed; to no avail. Finally, based on browsing lots of Web search results, I just guessed that, since my Cygwin has gcc version 3.4.4, I might have glibc version 2.3.5. I made the necessary changes in cygwin.inc and moved on.

The next issue was the os_kernel_version. The formula for extracting this in linux.inc is:


os_kernel_version:=$(shell uname -r | sed -e 's/-.*$$//')


I'm not up enough on my script writing and regular expressions to say at a blink what that means; but, for my version of Cygwin, it returned:


1.5.25(0.156/4/2)


which causes a problem further in the TBB build process (the parentheses are the problem). So, my temporary hack was to comment out the original os_kernel_version line and replace it with:


os_kernel_version:=1.5.25


In my cygwin.gcc.inc file, I commented out the arch testing and directly applied the ia32 flags:


CPLUS_FLAGS += -m32
LIB_LINK_FLAGS += -m32


Below that section of cygwin.gcc.inc there is a "Setting assembler data" section. This is an area where I expect problems, ultimately (I'd guess that I'll really need to use the Windows ASSEMBLY functions). But for now, I let it go and moved on, since I hadn't even got to the point where I could compile a *.cpp file.

After all these changes, I was able to execute make info and see the following results:


$ make info
OS: cygwin
arch=ia32
compiler=gcc
runtime=cc3.4.4_libc2.3.5_kernel1.5.25
tbb_build_prefix=cygwin_ia32_gcc_cc3.4.4_libc2.3.5_kernel1.5.25


Just what I wanted to see!

My next step, entering make all by itself, brought me to the next level: a string of error messages that resulted from the attempt to compile src/tbb/concurrent_hash_map.cpp, the first *.cpp file that is compiled in the TBB build process.

What was the nature of the error? Tracing it down, the problem is in include/tbb/tbb_machine.h. I'm ending up with several variables undefined, resulting in the compile being trapped on line 83, with the output message:


#error Minimal requirements for tbb_machine.h not satisfied


The variables that are not defined in my build are:

    • __TBB_CompareAndSwap4

    • __TBB_CompareAndSwap8

    • __TBB_Yield



Searching for where these are defined, I found them in the include/tbb/machine/*.h files, which are included in include/tbb/tbb_machine.h based on operating system variables. So, it looks like I'm going to have to create a cygwin setting within tbb_machine.h and create a corresponding Cygwin *.h file in the include/tbb/machine directory. The question is: will this look more like one of the Windows *.h files in that directory, or more like one of the Linux *.h files?

As a quick experimental hack, I hard-coded include/tbb/tbb_machine.h to include the include/tbb/machine/windows_ia32.h file. Retrying make ... returned many error lines talking about things like


... error: expected asm body before '{' token
... error: expected '(' before "mov"
... error: 'mov' undeclared (first use in this function)


In other words, I'm into the assembler issues I expected to meet up with at some point.

Next hack experiment: changing include/tbb/tbb_machine.h to include the include/tbb/machine/windows_ia32_inline.h file (maybe this would bypass the assembler difficulties?). Retry make ... and ... nope. Similar results.

Today's final experiment: change include/tbb/tbb_machine.h to include the include/tbb/machine/linux_ia32.h file. Once again, make ... and a different result this time! This time, this error ends the build:


In file included from ../../src/tbb/concurrent_queue.cpp:33:
../../src/tbb/tbb_misc.h:86:2: #error Unknown OS
make[1]: *** [concurrent_queue.o] Error 1


Now that looks like great progress to me! Looks like I need to go into src/tbb/tbb_misc.h and do some tailoring for Cygwin. I'll write about that effort and its results next time.

Kevin Farnham, O'Reilly Media TBB Open Source Community, Freenode IRC #tbb, TBB Mailing Lists

Download TBB

For more complete information about compiler optimizations, see our Optimization Notice.