From: Dominique D. <DDe...@lg...> - 2002-08-28 16:16:28
|
Hi, After hearing quite a bit about ant-contrib's cpptasks on ant-user/ant-dev, I finally tried yesterday to convert my old makefile-based (on Windows, using nmake) JNI dll compilation to <cc>. My build system already uses Ant extensively for all the Java code, even to compile (4 big) Visual Studio workspaces by <exec>ing msdev.exe, but these two JNI dlls and one exe were still resisting the Ant invader ;-) I hope this tale will encourage people to give the <cc> tasks a spin as well, now that cpptasks 1.0 beta 1 as been released. The first small JNI dll and the little exe were easily taken care of, since mostly independent code, only after I solved setup issues (I'll come back on those later). Thanks for the documentation of the tasks, it's quite nice. Having examples to follow would have helped, but thru experimentation and the good tasks docs, I managed to have things working faster than I thought I would. Actually, I would probably have given up without this early (lucky?) success. Anyways... The main JNI dll was what I was really interested on. It's the JNI layer on top of the 4 big MS VS workspaces (.dsw), each composed of many projects (.dsp). Adding to the <includepath> to compile was easy, offering many choices of types to pass on (<fileset>, <filelist>, <dirset>, etc...), but I was surprised to see how <libset> was poor in comparison... 1) <libset> No option to use a <filelist>, or even a <fileset> (if one doesn't care about the order of the libraries). And for my particular case, the many libs I need (around 10 per project) are all prefixed by the workspace name, which can be quite long. I short, instead of having to do: <libset dir="../../Vendor/AbcdefghijklmNopqrstu/bin/${config}" libs="AbcdefghijklmNopqrstu_archive, AbcdefghijklmNopqrstu_editing, AbcdefghijklmNopqrstu_proportions, AbcdefghijklmNopqrstu_upscaling, AbcdefghijklmNopqrstu_morphing, AbcdefghijklmNopqrstu_param2d, AbcdefghijklmNopqrstu_param3d, AbcdefghijklmNopqrstu_nutils, AbcdefghijklmNopqrstu_gapi" /> I'd like to be able to say: <libset dir="../../Vendor/AbcdefghijklmNopqrstu/bin/${config}" libprefix="AbcdefghijklmNopqrstu_" libs="archive, editing, proportions, upscaling, morphing, param2d, param3d, nutils, gapi" /> or: <libset dir="../../Vendor/AbcdefghijklmNopqrstu/bin/${config}"> <library name="AbcdefghijklmNopqrstu_archive" /> etc... </libset> or: <libset> <fileset dir="../../Vendor/AbcdefghijklmNopqrstu/bin/${config}"> <include name="*.lib" /> <exclude name="gui*" /> </fileset> </libset> In my particular case, using a <fileset> would have been convenient, since I could have re-used the same fileset (thanks to its 'id') in my distrib target as well, in addition as inside <libset> for <cc>. These are enhancement requests I guess. 2) Always recompiles Now on to something that might be a bug: After doing a clean build, I did several builds without changing anything, and <cc> still compiles a couple files, every time! I tried turning on debug in Ant, to find out why these two file appear out-of-date, but didn't get much debug output from <cc> at all. Of course, recompiling triggers a re-link, which is not that great. And just as I write this, it finally downed on me that I was using the same objdir for all my 3 <cc> invocations, and I had two files similarly names (although not with the same case, but Windows being what it is...). After I changed my build.xml to have different 'objdir' values, then it behaved perfectly. But that brings up another issue I think: The flattening of all objects in a single directory is bound to result trouble when the same source short name exists in different directories, and they all get compiles at the same time!!! My long term goal was to also use <cc> to compile the 4 big Visual Studio workspaces, instead of having msdev on windows, and gnu makes on the unix side... And I have such similarly named files belonging to different DLLs right now, but I wanted to compile 1 DLL per workspace (instead of 10) using a single <cc> invocation. In any case, it seems dangerous to not even detect collisions like that. 3) Env. Setup The documentation simply says: 4) Set path and environment variables to be able to run compiler from command line. That is simply not acceptable to me. One of the great things Ant provides is the ability to encapsulate all environment dependent things into user-specific properties files (under CM control). For example, to <exec> msdev.exe, I simply provide the right Path/LIB/INCLUDE paths using <env> sub-element. Since <cc> doesn't allow these types of arguments, I had to resort to having Ant <exec> Ant, setting the proper environment, and only then calling the target doing calling <cc>. Below is that setup, where I have a launcher, and launcher-cc task, with checks to ensure not calling the launcher-cc target directly, and checks to avoid infinite recursion. This makes for a very convoluted build.xml that could be tremenduously simplified if <cc> and/or <compiler> could have <cc-environment> or <compiler-env> encapsulating it (or just support the <env> sub-element like <exec>, but then there's less re-used possible), and using it when forking the compiler/linker. Right now, you fork them using the same environment as Ant's, and don't provide any way to change that environment. I think this is worst thing I've found about cpptasks, which I can turn around ('cause I know one thing or two about Ant ;-), but makes for a complex or hard to follow build.xml (and also needs starting up another VM and Ant instance!). Overall, I'm very pleased with <cc> / cpptasks, and I hope that this long winded messages of my experience with it might lead to the few changes I propose for 1.0 ;-) Thanks for such a great innovative tool. Best regards, --DD <!-- ========================== --> <target name="launcher" depends="-cc-call-forbid!" description="Compiles and link our custom Java launcher"> <antcall target="-cc-call"> <param name="target" value="launcher" /> </antcall> </target> <!-- ========================== --> <target name="launcher-cc" depends="-cc-call-ensure!, -cc-defs"> <!-- Make sure obj dir exits, as <cc> doesn't create it! --> <property name="bin" location="build/bin/x86" /> <mkdir dir="${bin}/com_lgc_java" /> <cc name="msvc" objdir="${bin}/com_lgc_java" outfile="${bin}/com_lgc_java" outtype="executable" runtime="dynamic" exceptions="true" incremental="false" multithreaded="true"> <fileset dir="src" includes="*.c" /> <includepath location="src" /> <syslibset libs="Advapi32" /> <defineset define="WIN32, LGC_SERVER" /> </cc> </target> <!-- ========================== Makes sure to avoid infinite recursion because of -cc-call. --> <target name="-cc-call-called?"> <condition property="-cc-call-called"> <equals arg1="${env.CALLCCC}" arg2="${env.INCLUDE}" /> </condition> </target> <target name="-cc-call-forbid!" depends="-cc-call-called?"> <fail message="Infinite loop!" if="-cc-call-called" /> </target> <target name="-cc-call-ensure!" depends="-cc-call-called?"> <fail message="Private target called!" unless="-cc-call-called" /> </target> <!-- ========================== Sets up correct environment for ant-contrib's <cc> task. --> <target name="-cc-call" depends="-cc-call-forbid!"> <property name="msdev.home" value="${env.VISUAL_STUDIO_ROOT}" /> <path id="cc-Path"> <pathelement location="${msdev.home}/Common/MSDev98/Bin" /> <pathelement location="${msdev.home}/Common/Tools" /> <pathelement location="${msdev.home}/VC98/bin" /> </path> <property name="cc-Path" refid="cc-Path" /> <property name="cc-LIB" location="${msdev.home}/VC98/lib" /> <property name="cc-INCLUDE" location="${msdev.home}/VC98/include" /> <path id="ant-CLASSPATH"> <fileset dir="${ant.home}/lib" includes="*.jar" /> </path> <property name="ant-CLASSPATH" refid="ant-CLASSPATH" /> <!-- Shows command lines and details dependency analysis --> <condition property="verboseArg" value="-verbose"> <istrue value="${verbose}" /> </condition> <property name="verboseArg" value="" /> <exec executable="${java.home}/../bin/java.exe" dir="${basedir}" vmlauncher="true" failonerror="true"> <arg value="-classpath" /> <arg path="${ant-CLASSPATH}" /> <arg value="org.apache.tools.ant.Main" /> <arg value="${verboseArg}" /> <arg value="-logger" /> <arg value="org.apache.tools.ant.NoBannerLogger" /> <arg value="-emacs" /> <arg value="-buildfile" /> <arg value="${ant.file}" /> <arg value="${target}-cc" /> <env key="Path" path="${cc-Path};${env.Path}" /> <env key="LIB" path="${cc-LIB}" /> <env key="INCLUDE" path="${cc-INCLUDE}" /> <env key="CALLCCC" value="${cc-INCLUDE}" /> </exec> </target> <!-- ========================== --> <target name="-cc-defs"> <taskdef resource="cpptasks.tasks" /> <typedef resource="cpptasks.types" /> </target> |
From: Curt A. <ca...@ho...> - 2002-08-29 02:08:58
|
From: "Dominique Devienne" <DDe...@lg...> wrote: > The first small JNI dll and the little exe were easily taken care of, since > mostly independent code, only after I solved setup issues (I'll come back on > those later). Thanks for the documentation of the tasks, it's quite nice. > Having examples to follow would have helped, but thru experimentation and > the good tasks docs, I managed to have things working faster than I thought > I would. Actually, I would probably have given up without this early > (lucky?) success. Anyways... There is a fairly complex sample build file for Xerces-C that I thought that I put into the distribution. If not, it is in the CVS as cpptasks/samples/xercesc.ant > The main JNI dll was what I was really interested on. It's the JNI layer on > top of the 4 big MS VS workspaces (.dsw), each composed of many projects > (.dsp). Adding to the <includepath> to compile was easy, offering many > choices of types to pass on (<fileset>, <filelist>, <dirset>, etc...), but I > was surprised to see how <libset> was poor in comparison... > > 1) <libset> > No option to use a <filelist>, or even a <fileset> (if one doesn't care > about the order of the libraries). If you are just adding library filenames to the linker command, you can just place the appropriate <fileset> as a child of a <linker> or <cc> element. For Microsoft Linker builds, <cc name="msvc"> ... <libset dir="${mylib.dir}" libs="mylib"/> </cc> is equivalent to: <cc name="msvc"> ... <fileset dir="${mylib.dir}" includes="mylib.lib"/> </cc> They would have different effects for GCC or similar compilers, libset would result in a "-L mydir -l mylib" fragment added to the command line, while <fileset> would result in "mydir/mylib.lib" being added to the command line. > > In my particular case, using a <fileset> would have been convenient, since I > could have re-used the same fileset (thanks to its 'id') in my distrib > target as well, in addition as inside <libset> for <cc>. These are > enhancement requests I guess. You could reuse the current form by placing the libset within a linker element and referencing or extending the linker. Earlier versions of cpptasks did allow <fileset> within <libset>, however it did not properly address the platform conventions ("lib" prefix and ".so" or ".a" extensions for gcc like compilers, no prefix and ".lib" extensions of Microsoft like compilers). I guess you could clone the FileSet and then add the prefixes and suffixes before evaluating the fileset, however that seems a decent amount of work. > > 2) Always recompiles > Now on to something that might be a bug: After doing a clean build, I did > several builds without changing anything, and <cc> still compiles a couple > files, every time! I tried turning on debug in Ant, to find out why these > two file appear out-of-date, but didn't get much debug output from <cc> at > all. Of course, recompiling triggers a re-link, which is not that great. I'll try to add more diagnostics when verbose. > > And just as I write this, it finally downed on me that I was using the same > objdir for all my 3 <cc> invocations, and I had two files similarly names > (although not with the same case, but Windows being what it is...). After I > changed my build.xml to have different 'objdir' values, then it behaved > perfectly. The expectation is that you would use distinct directories for different types of builds. Any change in the command line (other than the files names) or any change in the compiler identification string will result in the object file being marked out of date. I'll expand the comments to mention this. > But that brings up another issue I think: > The flattening of all objects in a single directory is bound to result > trouble when the same source short name exists in different directories, and > they all get compiles at the same time!!! My long term goal was to also use > <cc> to compile the 4 big Visual Studio workspaces, instead of having msdev > on windows, and gnu makes on the unix side... And I have such similarly > named files belonging to different DLLs right now, but I wanted to compile 1 > DLL per workspace (instead of 10) using a single <cc> invocation. In any > case, it seems dangerous to not even detect collisions like that. cpptasks should detect object filename collisions within one <cc> task (code around line 148 in TargetMatcher). For example, if you did: <cc> <fileset dir="foo1" include="foo.cpp"/> <fileset dir="foo2" include="foo.cpp"/> </cc> You should get a BuildException. There is no collision detection between distinct <cc> tasks in one build or multiple builds of the same project running simultaneously. However, I don't think any build tool robustly handles multiple instances competing for the same output directories. If you can build with Visual Studio, I would think that you already avoid building identically named object files in one project since they compile all their files for a configuration into one directory. Trying to create a tree structure in the build directory (like a Java build) is problematic when the source files come from locations that are not descendents of the build directory. > > 3) Env. Setup > The documentation simply says: 4) Set path and environment variables to be > able to run compiler from command line. That is simply not acceptable to me. > One of the great things Ant provides is the ability to encapsulate all > environment dependent things into user-specific properties files (under CM > control). Definitely, you would like to avoid putting any compiler or installation specific settings in the body of a build script. The current approach avoids that by expecting that the compiler is on the path or that you have run VCVARS32.bat. I'd try to add a newenvironment attribute and allowing <env> children for <linker>, <compiler> and <cc>. It don't think that cc-environment would add any additional reuse since the environment variables almost always be associated with one specific compiler, so you could just add then to a base <compiler> element that similar <compiler>'s extend. |