programming

Jimmy 2008. 10. 13. 16:18
Okay, I think I finally figured it out.
 
Getting ICU to build as static libraries on Windows required two changes to the code.  The first is the one I outlined in my previous note: In common/utracimp.h, the definition of utrace_level needs to be modified to not include U_EXPORT when U_STATIC_IMPLEMENTATION is defined.  The relevant section of the file should end up looking like this:
 
#ifdef UTRACE_IMPL
U_EXPORT int32_t
#elif defined(U_COMMON_IMPLEMENTATION)
U_CFUNC int32_t
#elif defined(U_STATIC_IMPLEMENTATION)
U_CFUNC int32_t

#else
U_CFUNC U_IMPORT int32_t
#endif
utrace_level;
 
The two lines I added are highlighted in bold (I also added the "defined(" stuff, which I think is just an oversight in the current version of this file).
 
The second change is to common/udata.c.  Line 652 in this file looks like this:
 
extern  const DataHeader U_IMPORT U_ICUDATA_ENTRY_POINT;
 
The U_IMPORT shouldn't be there when you're building as static libraries (this is what was causing the funny symbol mangling I was seeing).  This should probably be fixed with some kind of conditional compilation akin to what's going on in utracimp.h, where you define some symbol in the makefile that controls whether we say U_IMPORT here or not, but I didn't want to figure out what should control that; I just commented out U_IMPORT.
 
These two changes, plus a fair amount of messing around with the project files and manually building things at the command line, will get the data, common, and i18n modules built as static libraries.  I wrote a little sanity check program that links against these files and it builds and runs correctly.
 
So to summarize, I think you follow these steps to build ICU as a static library on Windows with MSVC6:
 
1) Make the change to utracimp.h described above (but not the change to udata.c).  Then build the source as-is (as DLLs) with MSVC, following the instructions in the readme.  This will build all the data files and allow you to run the unit tests.  You should get no test failures.
 
2) There will be a file called icudt28l_dat.obj in source/data/out/build.  I believe your program can link to this directly, or you can make it into a static library by just doing lib /out:icudata.lib idudt28l_dat.obj at the command line.  You can also hack makedata.mak as described in George's earlier email (I'm pretty sure both methods work).  The resulting library will work with both debug and release builds and with any MSVC threading model, as far as I can tell.  [I chose sicudata.lib as the filename for the lib file just so the names were consistent with the names they get on the Unix platforms.]
 
3) Now go into udata.c and make the change described above.
 
4) Go back into MSVC and choose Settings from the Project menu.  Choose "common" as the project to modify.  In the defines list, change "U_COMMON_IMPLEMENTATION" to "U_STATIC_IMPLEMENTATION".  It necessary, change "/MD" to whatever trheading model you're using.  Set "common" as your active project and choose Rebuild All from the Build menu.  The .c and .cpp files should all compile, but you'll get an undefined-symbol error from the linker.  This is okay.  Repeat this step for both the debug and release configurations.
 
5) Go into source\common\Release and execute lib /out:sicuuc.lib *.obj.  This will create a static library for "common".  Issue the same command inside source\common\Debug.  In both cases, the name I'm using-- sicuuc.lib-- was chosen to be consistent with the Unix builds.
 
6) "i18n" won't build from within MSVC because of the link error in "common".  Go into source\i18n and build it by hand using cl.  Copy the compiler options from the Project Settings window.  Change "/D U_I18N_IMPLEMENTATION" to "/D U_STATIC_IMPLEMENTATION".  You should be able to build everything by specifying the input filename as "*.c *.cpp", rather than issuing a separate cl command for each file.
 
7) You can now assemble everything into a library with "lib /out:sicui18n.lib *.obj" in whatever directory you sent the compiler output to.  You'll have to repease steps 6 and 7 to do both debug and release builds.
 
8) You're done!  If (as I did) you need to support different threading models, repeat steps 4 through 6 for the different threading models you need to support.
 
Caveat: These are not the exact steps I followed to get everything built.  My route was more circuitous, as it involved trying different things until I fugured out what worked.  So I can't guarantee the steps I give above will work perfectly, but it's what I think the sequence is now that I got everything built.
 
Anyway, problem solved, and there's the wisdom I gleaned in case anyone else out there tries to do the same thing.
 
Life would be so much easier if everyone coded in Java!  :-)
 
Thanks...
 
--Rich Gillam
  Language Analysis Systems, Inc.