There is nothing special about the ivy files from the standard documentation 
except that I introduced some custom XML properties to help me with the 
artifact pattern.

<?xml version="1.0" encoding="UTF-8"?>
<ivy-module version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:noNamespaceSchemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd"; 
xmlns:ext="http://ant.apache.org/ivy/extra";>
        <info organisation="Company" module="testModule">
                <repository name="Subversion" url="${env.SVN_URL_REVISION}"/>
                <description>This module contains the test module.</description>
        </info>
        <configurations>
                <conf name="all"/>
                <conf name="win32"/>
                <conf name="win64"/>
                <conf name="linux32"/>
                <conf name="linux64"/>
                <conf name="solaris"/>
        </configurations>
        <publications>
                <artifact name="com_company_test_module" type="jar" ext="jar" 
ext:path=""/>
                <artifact name="include" type="include" ext="zip" ext:path=""/>
                <artifact name=" com_company_test_module " ext="dll" type="bin" 
ext:path="win32" conf="all,win32"/>
                <artifact name=" com_company_test_module " ext="dll" type="bin" 
ext:path="win64" conf="all,win64"/>
                <artifact name=" com_company_test_module " ext="so" type="bin" 
ext:path="linux32" conf="all,linux32"/>
                <artifact name=" com_company_test_module " ext="so" type="bin" 
ext:path="linux64" conf="all,linux64"/>
                <artifact name=" com_company_test_module " ext="so" type="bin" 
ext:path="solaris" conf="all,solaris"/>
        </publications>
                <dependencies>
                        <dependency name="depModule" rev="latest.testing" 
conf="*->@"/>
                </dependencies>

</ivy-module>


Below is my post processing ant code that scans dependencies directory looking 
for include.zip files and unzipping them, or symbolic links to be made, or 
execute bits to be set.  All of this is keyed off of custom IVY XML properties 
which make this stuff pretty easy.  I don't have time to clean up this code to 
make it easier for you, so good luck sorting through it.


   <target name="dependencies.process" depends="init.ivy">
      <!--Perform post dependency processing-->
      <condition property="isUnix">
         <isfalse value="${isWindows}"/>
      </condition>
      <ac:for param="dependencyDir">
         <dirset dir="${env.DEPENDENCIES_DIR}">
            <include name="*"/>
         </dirset>
         <sequential>
            <ac:var name="dependencyName" unset="true"/>
            <basename file="@{dependencyDir}" property="dependencyName"/>
            <!--Check for dependency subsetting and remove those artifacts that 
do not belong-->
            <!--Search for any symbolic links that need to be made-->
            <ac:var name="dependencySubsets" unset="true"/>
            <ac:if>
               <isset property="${dependencyName}.subsets"/>
               <ac:then>
                  <ac:propertycopy property="dependencySubsets" 
from="${dependencyName}.subsets"/>
                  <echo message=":: Keeping only subsets: ${dependencySubsets} 
from module: ${dependencyName}"/>
               </ac:then>
            </ac:if>
            <ac:if>
               <available file="@{dependencyDir}/ivy/ivy.xml"/>
               <ac:then>
                  <xt:xmltask source="@{dependencyDir}/ivy/ivy.xml" 
failWithoutMatch="false">
                     <xt:call path="ivy-module/publications/artifact">
                        <param name="artifactName" path="@name"/>
                        <param name="artifactExt" path="@ext"/>
                        <param name="artifactType" path="@type"/>
                        <param name="artifactPath" path="@ext:path"/>
                        <param name="artifactAliases" path="@ext:aliases" 
default=""/>  <!--Custom IVY XML property to show symbolic links to be made-->
                        <param name="artifactZip" path="@ext:zip" 
default="false"/>  <!--Custom IVY XML property to show files that need 
unzipping-->
                        <param name="artifactExecutable" path="@ext:executable" 
default="false"/>  <!--Custom IVY XML property to show a file that needs 
execute bit set on unix-->
                        <xt:actions>
                                 <ac:if>
                                    <isfalse 
value="${dependencies.skipSymbolicLinks}"/>
                                    <ac:then>
                                       <!--Process symbolic links-->
                                       <ac:for param="artifactAlias" 
list="@{artifactAliases}">
                                          <sequential>
                                              <ac:if>
                                             <and>
                                                 <available 
file="@{dependencyDir}/@{artifactType}/@{artifactHome}/@{artifactHomeType}/@{artifactPath}"
 type="dir"/>
                                                 <available 
file="@{dependencyDir}/@{artifactType}/@{artifactHome}/@{artifactHomeType}/@{artifactPath}/@{artifactName}.@{artifactExt}"
 type="file"/>
                                                 <not>
                                                <available 
file="@{dependencyDir}/@{artifactType}/@{artifactHome}/@{artifactHomeType}/@{artifactPath}/@{artifactAlias}"
 type="file"/>
                                                 </not>
                                             </and>
                                             <ac:then>
                                                 <echo message="Creating 
symbolic link: @{artifactAlias}->@{artifactName}.@{artifactExt}"/>
                                                 <ac:if>
                                                    <istrue 
value="${isWindows}"/>
                                                    <ac:then>
                                                       <copy 
file="@{dependencyDir}/@{artifactType}/@{artifactHome}/@{artifactHomeType}/@{artifactPath}/@{artifactName}.@{artifactExt}"
 
tofile="@{dependencyDir}/@{artifactType}/@{artifactHome}/@{artifactHomeType}/@{artifactPath}/@{artifactAlias}"/>
                                                    </ac:then>
                                                    <ac:else>
                                                       <se:smartexec 
executable="ln" dir="${basedir}" failonerror="true" showCommand="false" 
ignorePrepend="true" if="isUnix">
                                                         <arg value="-s"/>
                                                         <arg 
value="@{artifactName}.@{artifactExt}"/>
                                                         <arg 
value="@{dependencyDir}/@{artifactType}/@{artifactHome}/@{artifactHomeType}/@{artifactPath}/@{artifactAlias}"/>
                                                       </se:smartexec>
                                                    </ac:else>
                                                 </ac:if>
                                             </ac:then>
                                             <ac:elseif>
                                                <available 
file="@{dependencyDir}/@{artifactType}/@{artifactHome}/@{artifactHomeType}/@{artifactPath}/@{artifactAlias}"
 type="file"/>
                                                <ac:then>
                                                    <echo message="Symbolic 
link already exists: @{artifactAlias}->@{artifactName}.@{artifactExt}"/>
                                                </ac:then>
                                             </ac:elseif>
                                              </ac:if>
                                          </sequential>
                                       </ac:for>
                                    </ac:then>
                                 </ac:if>
                                 <!--Process zips that should be extracted-->
                                 <ac:if>
                                    <and>
                                       <available 
file="@{dependencyDir}/@{artifactType}/@{artifactHome}/@{artifactHomeType}/@{artifactPath}/@{artifactName}.@{artifactExt}"/>
                                       <or>
                                          <istrue value="@{artifactZip}"/>
                                          <and>
                                             <equals arg1="@{artifactType}" 
arg2="include"/>
                                             <matches string="@{artifactName}" 
pattern="include.*"/>
                                             <equals arg1="@{artifactExt}" 
arg2="zip"/>
                                          </and>
                                       </or>
                                    </and>
                                    <ac:then>
                                       <unzip 
src="@{dependencyDir}/@{artifactType}/@{artifactHome}/@{artifactHomeType}/@{artifactPath}/@{artifactName}.@{artifactExt}"
 
dest="@{dependencyDir}/@{artifactType}/@{artifactHome}/@{artifactHomeType}/@{artifactPath}"/>
                                       <delete 
file="@{dependencyDir}/@{artifactType}/@{artifactHome}/@{artifactHomeType}/@{artifactPath}/@{artifactName}.@{artifactExt}"/>
                                       <!--Process zip executables that should 
be set-->
                                       <ac:if>
                                          <istrue 
value="@{artifactExecutable}"/>
                                          <ac:then>
                                             <echo message="Setting executable 
bit on contents of zip: 
@{dependencyDir}/@{artifactType}/@{artifactHome}/@{artifactHomeType}/@{artifactPath}/@{artifactName}.@{artifactExt}"/>
                                             <se:smartexec executable="chmod" 
dir="${basedir}" failonerror="true" showCommand="false" ignorePrepend="true" 
if="isUnix">
                                                <arg value="-R"/>
                                                <arg value="a+x"/>
                                                <arg 
value="@{dependencyDir}/@{artifactType}/@{artifactHome}/@{artifactHomeType}/@{artifactPath}"/>
                                             </se:smartexec>
                                          </ac:then>
                                       </ac:if>
                                    </ac:then>
                                 </ac:if>
                                 <!--Process executables that should be set-->
                                 <ac:if>
                                    <and>
                                       <available 
file="@{dependencyDir}/@{artifactType}/@{artifactHome}/@{artifactHomeType}/@{artifactPath}/@{artifactName}.@{artifactExt}"/>
                                       <istrue value="@{artifactExecutable}"/>
                                    </and>
                                    <ac:then>
                                       <echo message="Setting executable bit: 
@{dependencyDir}/@{artifactType}/@{artifactHome}/@{artifactHomeType}/@{artifactPath}/@{artifactName}.@{artifactExt}"/>
                                       <se:smartexec executable="chmod" 
dir="${basedir}" failonerror="true" showCommand="false" ignorePrepend="true" 
if="isUnix">
                                          <arg value="a+x"/>
                                          <arg 
value="@{dependencyDir}/@{artifactType}/@{artifactHome}/@{artifactHomeType}/@{artifactPath}/@{artifactName}.@{artifactExt}"/>
                                       </se:smartexec>
                                    </ac:then>
                                 </ac:if>
                        </xt:actions>
                     </xt:call>
                  </xt:xmltask>
               </ac:then>
            </ac:if>
         </sequential>
      </ac:for>
   </target>


How I build my classpath:

   <target name="module.classPath" 
depends="module.jarPath,module.eclipseClassPath,dependencies.check">
      <mkdir dir="${env.DEPENDENCIES_DIR}"/>
      <mkdir dir="${env.BUILD_DIR}/classes"/>
      <path id="moduleClassPath">
         <pathelement location="${env.BUILD_DIR}/classes"/>
         <path refid="moduleJarPath"/>
         <path refid="moduleEclipseClassPath"/>
         <fileset dir="${env.DEPENDENCIES_DIR}">
            <include name="**/jar/*.jar"/>
         </fileset>
      </path>
      <!--Make available as a property as well-->
      <pathconvert property="moduleClassPath" refid="moduleClassPath"/>
      <ac:if>
         <istrue value="${verbose}"/>
         <ac:then>
            <echo message="moduleClassPath=${moduleClassPath}"/>
         </ac:then>
      </ac:if>
   </target>



How I set my INCLUDE_DIR and BINARY_DIR env variables to pass to visual studio 
and stuff:

   <target name="dependencies.check" depends="init.ivy">
      <mkdir dir="${env.DEPENDENCIES_DIR}"/>
      <!--Set env properties based on where dependency module artifacts exist-->
      <ac:for param="dependencyDir">
         <dirset dir="${env.DEPENDENCIES_DIR}">
            <include name="*"/>
         </dirset>
         <sequential>
            <ac:var name="dependencyName" unset="true"/>
            <basename file="@{dependencyDir}" property="dependencyName"/>
            <at:stringutil property="dependencyNameUpper" 
string="${dependencyName}">
               <at:uppercase/>
            </at:stringutil>
            <property name="env.${dependencyNameUpper}_INCLUDE_DIR" 
value="@{dependencyDir}${file.separator}include"/>
            <property name="env.${dependencyNameUpper}_PLATFORM_INCLUDE_DIR" 
value="@{dependencyDir}${file.separator}include${file.separator}${os.platform}"/>
            <property name="env.${dependencyNameUpper}_BINARY_DIR" 
value="@{dependencyDir}${file.separator}bin${file.separator}${os.platform}"/>
         </sequential>
      </ac:for>
      <ac:if>
         <istrue value="${verbose}"/>
         <ac:then>
            <echoproperties regex="env\..*_INCLUDE_DIR"/>
            <echoproperties regex="env\..*_BINARY_DIR"/>
         </ac:then>
      </ac:if>
   </target>



How I pass these env variables to my launch of visual studio and stuff  
(smartexec is the same as exec but I enhanced it a bit, you can probably use 
regular exec here):

      <macrodef name="launchNative" description="Runs an arbitrary command with 
full runtime environment">
         <attribute name="executable"/>
         <attribute name="spawn" default="true"/>
         <attribute name="returnCodeProperty" default=""/>
         <element name="arguments" optional="true" implicit="true"/>
         <sequential>
             <se:smartexec executable="@{executable}" dir="${basedir}" 
spawn="@{spawn}" ignorePrepend="true" showCommand="false" failonerror="false" 
resultproperty="@{returnCodeProperty}">
               <arguments/>
               <env key="DEPENDENCIES_DIR" value="${env.DEPENDENCIES_DIR}"/>
               <envset>
                  <propertyref regex="env\..*_INCLUDE_DIR"/>
                  <mapper type="regexp" from="env\.(.*_INCLUDE_DIR)" to="\1"/>
               </envset>
               <envset>
                  <propertyref regex="env\..*_BINARY_DIR"/>
                  <mapper type="regexp" from="env\.(.*_BINARY_DIR)" to="\1"/>
               </envset>
               <env key="BUILD_DIR" value="${env.BUILD_DIR}"/>
               <env key="${runtimeLibPathVar}" path="${runtimeLibPath}"/>
            </se:smartexec>
         </sequential>
      </macrodef>
---
Shawn Castrianni

-----Original Message-----
From: Scott Palmer [mailto:[email protected]]
Sent: Monday, April 11, 2011 3:01 PM
To: [email protected]
Subject: Re: Ivy for C/C++ libraries

Excellent!  This gives me some confidence that this will work for me. Since it 
has been done before, hopefully won't have to fight too hard to get this 
working.

Do you have any sample ivy files you could share that would nudge me in the 
right direction?  Last time I checked I couldn't find any examples on the Ivy 
site or via google that did this sort of thing.  Just the first couple steps 
would be helpful.

I have very little experience with Ivy.. basically only for simple Java 
projects and Ivy + Ant (+the IvyBeans NetBeans plugin) magically do what I 
want.  Things end up on my classpath and I don't know exactly how that happens. 
 Something as as simple as the right way to do the post-processing Ant task to 
unzip header files and how you set your <module>_INCLUDE_DIR would be helpful.  
I've already got Ant calling out to Visual Studio - it a matter of getting the 
build environment configured with all the dependencies that I'm working out at 
this point.

Thanks,

Scott

On 2011-04-11, at 3:00 PM, Shawn Castrianni wrote:

> I have posted several messages to this user group concerning this topic.  
> Here is a short summary of what I have done:
>
> 1. Use IVY configurations to separate out the different artifacts for
> the different platforms 2. I zip up the header files and run a
> post-processing ant task to unzip them after the IVY resolve and
> retrieve are complete 3. I leave the dll's and so's as separate
> artifacts specifying their correct configuration so that when downloading 
> artifacts on win32, only win32 artifacts are retrieved 4. I set ant 
> properties called <module>_INCLUDE_DIR and <module>_BINARY_DIR that point to 
> the include and "bin/<platform>" subdirectories so that include paths and 
> library paths can be set more easily 5. I build everything in ANT which 
> either call visual studio devenv command line utility to build from the 
> vcproj files on windows  OR  do one of three things on unix platforms.
>       a. use exec to call the compiler commands directly
>       b. use exec to call legacy build scripts like make
>       c. use cpptasks
>
> It all works very well.
>
> ---
> Shawn Castrianni
>
>
> -----Original Message-----
> From: Scott Palmer [mailto:[email protected]]
> Sent: Monday, April 11, 2011 1:44 PM
> To: [email protected]
> Subject: Ivy for C/C++ libraries
>
> I want to use Ivy to manage some projects that use both Java and C+_+.  For 
> the C++ side we have several 3rd-party SDKs that we need to use.  These 
> basically contain header files (.h) and lilbraries for linking (.lib) and DLL 
> files needed to deploy.
>
> I was thinking of storing the 3rd-party SDKs as ZIPs and have some automated 
> process to un-zip them to a known location e.g.  %SDKS%\module_name\* so the 
> C++ code could find them.  But if it is easier to deal with the individual 
> files as assets then I could do that as well.
>
> Is there any sort of sample or tutorial that would help cover this case?
> It seems the examples are very java-centric, I am likely not going to be 
> using Ant when building the native parts of the project, so I would like to 
> call Ivy directly.. but I'm not against making an Ant wrapper that invokes 
> the native build process as well.
>
> Regards,
>
> Scott
>
> ----------------------------------------------------------------------
> This e-mail, including any attached files, may contain confidential and 
> privileged information for the sole use of the intended recipient.  Any 
> review, use, distribution, or disclosure by others is strictly prohibited.  
> If you are not the intended recipient (or authorized to receive information 
> for the intended recipient), please contact the sender by reply e-mail and 
> delete all copies of this message.

Reply via email to