Msbuild example for Clarion

I originally posted this as a gist but never wrote a blog or otherwise published it. Maybe someone here will find it helpful!

msbuild example for Clarion

This is an example of how to build a Clarion multi dll project from the command line.
This was useful to be able to correctly build a multi-dll project containing circular references.


The BAT file

There are two calls so everything gets compiled.
Output is piped to log files for later reference

%windir%\Microsoft.NET\Framework\v2.0.50727\MSBuild master.msbuild /p:ClarionBinPath="c:\Clarion8\bin" /p:NoDependency="true" /p:Configuration="Release" /p:CopyCoreFiles="true" /target:First > build_first.log
%windir%\Microsoft.NET\Framework\v2.0.50727\MSBuild master.msbuild /p:ClarionBinPath="c:\Clarion8\bin" /p:NoDependency="true" /p:Configuration="Release" /p:CopyCoreFiles="true" /target:Second > build_second.log

contents of master.msbuild:

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Circular"  
  xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <ItemGroup>
        <FirstPass Include="global.cwproj;
  	manager.cwproj;
		sec.cwproj;
		integration.cwproj;
		utils.cwproj;
		scheduler.cwproj;
		reports.cwproj;
		settings.cwproj;
		import.cwproj;
		orders.cwproj;
		quotes.cwproj;
		products.cwproj;
		servicemgr.cwproj;
		knowledgetree.cwproj;
		crm.cwproj;
		"/>
    </ItemGroup>
    <ItemGroup>
        <SecondPass Include="integration.cwproj;
        	quotes.cwproj;
		orders.cwproj;
		servicemgr.cwproj;
		master.cwproj;
		"/>
    </ItemGroup>
    <Target Name="First">
        <MSBuild Projects="@(FirstPass)"  
          Targets="Build" ContinueOnError="true" />  
    </Target>
    <Target Name="Second">
        <MSBuild Projects="@(SecondPass)"  
          Targets="Build" ContinueOnError="true" />  
    </Target>
</Project>

Original Gist:

3 Likes

Hey Brahn, what’s the reasoning for two parts, why couldn’t you put all your apps into the first list?

Circular dependencies in the case of this solution. Clarion PE does not include the smarts to deal with the multiple compiles needed to resolve the problem so I solved it this way instead :slight_smile:

Instead we have a hand coded project that includes a .prj with a bunch of #implib statements that creates all of the libs from all of the EXPs. That way we can do a single pass compile.
– c/o @d.harms

Neat idea Dave, thanks!


Excerpt From ā€œBasic Compiling and Linkingā€

#implib

#implib <libfilename>

The #implib command is used to create (if necessary) a dynamic link library file. There are two forms of this command, which operate in slightly different ways. If a single filename is specified, this names an import library file, which is created (if not up-to-date) from the object files in the link list. The object files are scanned and each public procedure or variable is exported. For example:

#pragma link( fred.obj, joe.obj )
#implib mylib.lib

In the second form of the #implib command, an import library filename and a module definition file (.exp—see Module Definition File below) are both specified, and the library file is created (if not up-to-date) from the symbols named in the definition file. This form of the command is equivalent to using the tsimplib utility that comes with SoftVelocity C, C++, and Modula-2.

#implib <expfilename> <libfilename>

Using #implib in the second form requires you to create and maintain the list of exports ā€˜by hand’, whereas the first form exports all public names automatically. The use of a module definition file is an advantage if you need to maintain compatibility with previous versions of an interface, and it also allows you to export only the procedures which need to be exported.

When #implib is used with a module definition file, the link list is cleared.


2 Likes

Good stuff Brahn, thanks. And thanks DH!

On a somewhat related subject.
Here is a batch file (.cmd is the same as .bat), That I use to call MsBuild.
It’s part of the Clarion package for use in Sublime Text, and VS Code
It’s designed to take arguments, because I call it via the Sublime Text build project system
A given project is configured for what to compile, the configuration (build or release) and version of clarion - given by a folder

Note in ST3, packages are distributed in a zipped form
so you’ll need to extract the .cmd from inside of the package to be able to call it.

In your Sublime Text Project settings:
ā€œbuild_systemsā€:
[
// see http://docs.sublimetext.info/en/latest/reference/build_systems.html
{
ā€œnameā€: ā€œClarionā€,
ā€œcmdā€: [
ā€œ${packages}\..\Installed Packages\CompileCW.cmdā€,

             // What to build, convention is the same folder and basename as this sublime-project file, but with a .sln instead
             "${project/\\.sublime-project/\\.sln/}",

             // Build Configuration typcially Debug|Release  
             "Debug",
             // "Release",

             "C:\\SV\\Clarion10.0.12567",

             //(Optional) CW_Ver, such as "8.0.9579" will default to current
             ""                   
    ],
    //uses perl style regex: (maybe this) http://www.cs.tut.fi/~jkorpela/perl/regexp.html
    "file_regex": "^  \\s*[2>]*(.*)\\(([0-9]*),([0-9]*)" 
    // hard code in the 2 spaces at the start of the line, to JUST use the final summary error lines
    // CON: this means I can't click on rows as the compile occurs
    // PRO: In line error messages are no longer duplicated

    //"working_dir": "${project_path}:${folder}}",
    //"shell" : true,           
}
1 Like

Handling circular references with #implib

I found Dave Harms had written the above a CMag article on the topic of using #ImpLib with nice screen captures. Be aware the article example uses the wrong syntax that flips the file names as LIB EXP. In his post here he shows it right as #ImpLib DllA.EXP DllA.LIB

I used the Article to make an example using DLL Tutor that I attached.

  1. Make a Win32 Project with a CLW that has nothing but MAP. CODE
  2. Make a LibCreate.PR file like below and add it to the SLN under Projects to Include
    ---- LibCreate.PR ----
    #implib ALLFILES.EXP ALLFILES.LIB
    #implib REPORTS.EXP REPORTS.LIB
    #implib UPDATES.EXP UPDATES.LIB

I don’t use this, I do a 3 pass MSBuild of DLLs, DLLs with Mutual Imports, EXEs. I’m not entirely sure how ImpLib can work with source control and multiple developers. It seems like a ā€œchicken and egg problem.ā€ The EXP file needs to be in Source control for use by the build server to perform #ImpLib. That file is generated and I’m not sure how stable it is so will it merge well?

ImpLibExampleForDllTutor.zip (2.5 KB)

Dave’s article had the correct syntax of #implib LIB EXP, it was wrong as #implib EXP LIB in the excerpt from page 130 of AdvancedTopicsReferenceGuide.pdf, the example projects in that PDF do show correctly e.g. #implib %%drvname%%.LIB %%drvname%%.EXP. The wrong syntax will trash your EXP and not give you a LIB.

I attached a corrected DLL Tutor example project to generate LIBs with the bwlow syntax. There’s not need to do AllFiles since if it is the first one built.
#implib ALLFILES.LIB ALLFILES.EXP
#implib REPORTS.LIB REPORTS.EXP
#implib UPDATES.LIB UPDATES.EXP

I also changed its target to a LIB so there’s never a pointless EXE, and then in the Post Build Cmd is DEL LibCreate.lib

My tests show this is optimized to only make the new LIB if it changes, i.e. if you run it twice in a row the LIB is not created again. I would guess it makes it, checks its the same, then does not replace it, but I did not test this. The project language does allow ā€œ#if reports.lib #older reports.exp #then #implib ā€¦ā€

ImpLibExampleForDllTutor_Corrected.zip (12.4 KB)

1 Like

I realized this is not a check-n-egg problem and will work perfectly. Unlike interactive building using the IDE when you build in a Batch mode:

  1. First you Generate CLWs for every APP and that makes the EXP files for every DLL
  2. Next you run MSBuild on all the CwProj’s to compile the CLWs that were generated

The first CwProj simply needs to be the Lib Creator. I like this idea and will try it next week so I can take out step 2 of the MSBUILD that re-compiles the DLLs with mutual imports.

The one possible issue is since Clarion 7 you can skip the EXP file and specify EXPORT on a procedure or data. This is similar to C++ declspec(dllexport). The Linker will add it to the LIB file and not the EXP so #implib would make a bad file. I almost never do this, and only for quick and dirty tests or prototypes. I tried it but decided I liked the EXP because I use it for other things.

You can use LibMaker to go get the mangled name, then edit the EXP to add it. You must remove EXPORT from the procedure or it will be a duplicate. (Or easier, prototype in the importing project and the linker errors will have the mangled names it wants.)

FEATURE: New attribute for procedure prototypes and static variables declarations: EXPORT. The EXPORT attribute forces the variable or procedure to be added to the export list of the DLL even if it is not listed in the EXPORTS section of the EXP file.

There is also this feature. I forgot the reasons, I guess its like Name(ā€˜xxx’). It can be found in other build systems like Visual Studio.

FEATURE: Ability to use substitution of exported name in the EXPORTS section of the EXP file. The entry in the EXPORTS section can have format [=] @?

The below DOS command will create the #implib lines in file ImpLib.TXT to paste into the .Pr file. This assumes the EXP files are present. It checks IF Exist .EXE and does not generate those.

DEL ImpLib.TXT & FOR %f IN (*.exp) DO IF not EXIST %~nf.EXE ECHO #implib %~nf.LIB %f >> ImpLib.TXT

In a BAT file you need % doubled to %%

@ECHO OFF
ECHO This will make a ImpLib.TXT file with all the lines for the PR 
pause
del implib.txt
FOR %%f IN (*.exp) DO IF not EXIST %%~nf.EXE ECHO #implib %%~nf.LIB %%f >> ImpLib.TXT
Notepad ImpLib.TXT

In one small project (8 DLL / 5 EXE) the second pass to compile the 4 DLL APPs with mutual imports only took 9 seconds. So skipping pass 2 by changing to use #implib will not see time any significant time savings. It will eliminate import errors on the first pass, and the build order will no longer matter (but I would try to do them in order). its the way to go.

1 Like

This is very nice @CarlBarnes. Just used this technique on a project with some circular references where I was building into a new project folder that had never been built in.
I added the .PR with the implib statements to my data DLL since it always gets compiled first, rather than a separate project.

2 Likes

Thank you for the reminder on this! I have a C5 project where a Single DLL compiles to export 24 Classes. I need to split that into 24 DLLs of one class each. I first wrote a program to split the 3000 line EXP into 24 files. Them I used this to make 24 LIBs.

I’ll list the steps I took to make it easier to do this next time:

  1. Create the ImpLib2Txt.BAT file in post #10 in the Project folder
  2. Run ImpLib2Txt.BAT to create ImpLib.TXT with #ImpLib lines
  3. Download ImpLibExampleForDllTutor_Corrected.zip attached in post 8
  4. Unzip in your project folder
  5. Edit LibCreate_ImpLib_prj.PR to add the #ImpLib lines from ImpLib.Txt in step 2
  6. In Clarion Open LibCreate_ImpLib.cwproj
  7. Build and it should make all your LIBs

Screen captures from steps 1 2 5 7


The reason I’m doing this is the Classes have Topspeed File declarations in the Class CLW. The C5 builds fine with those files are encapsulated as local. In C8 - C11.1 build throws duplicate symbol errors on the Keys. I’d say the compiler is making them public for the linker. So I am trying putting each Class in its own DLL since those KEY symbols are not DLL public.

1 Like

Has anyone created a template for the MS Build system, ie parsing and reading it in into a template which can be used to make settings changes before exporting it back? I cant find anything suggesting a template exists searching this forum and relevant posts eg
Get Compiler Version & Build Config for use in a PostCompile Build action - code / Snippets - ClarionHub

msbuild example for Clarion Ā· GitHub
Too much hand code for my liking, I’d rather modify it from within a template that guides the decision making process.

And is this factually correct, you cant alter the project settings when using the appgen in C6 or early?

TIA

You might be able to. And if you’re not, there’s nothing stopping you from generating an external .prj (a la Capesoft multiprj)

I’m currently generating my own prj file from my templates, I didnt know about capesofts multiprj. Now I know. :grinning:

Here are the basics for building a call to msbuild to compile your .cwproj files.

"<msbuildPath>\msbuild.exe" msbuild.exe /property:NoDependency=true /property:ClarionBinPath="<Path to Clarion.exe>" /l:FileLogger,Microsoft.Build.Engine;logfile="<Path to log file>";Append=true "<Path to .cwproj>"

You can include optional parameters after the ClarionBinPath like:

/property:Configuration=[Debug|Release]
/property:clarion_version=ā€œclarionversionā€

The clarion_version property is used when you are using the IDE’s ā€œversionā€ feature. In other words, you are using one IDE to compile with multiple different Clarion installation you have on disk. See the help topic ā€œVersions - adding to the IDEā€

The installed version of msBuild can be found in the registry Local Machine: HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\MSBuild\ToolsVersions

1 Like

In discussion on Clarion Live with @PeterPetropoulos about this topic here’s an example of Build and BAT files I use often.

These BAT files have had lots of problem checking added making them longggggg.

00BldEisPayroll.msbuild file is specified in the call to MS Build in 00Bld2Compile.BAT

<Project DefaultTargets="Circular"  xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <ItemGroup>
        <!-- put problems in Pass 0 to be done manually (optionally) -->
        <Pass0PrjDLL Include="
                  pr00.cwproj;
                  pr01.cwproj;
		          "/>
    </ItemGroup>
    <ItemGroup>
        <Pass1PrjDLL Include="
                  LibCreate_ImpLib.cwproj;
                  prmsgbx.cwproj;
                  pr03.cwproj;
                  pr05.cwproj;
                  pr06.cwproj;
                  pr07.cwproj;
                  pr08.cwproj;
                  pr20.cwproj;
                  pr21.cwproj;
                  pr22.cwproj;
                  pr23.cwproj;
                  pr25.cwproj;
                  pr02.cwproj;
		          "/>
    </ItemGroup>
    <!-- Build again Pass 1 Proj with Mutual Imports / Circle Call Refs -->
    <!-- This should NOT be required now that the LibCreate_ImpLib.cwproj above uses #implib to make LIBs from EXP -->
    <ItemGroup>
        <Pass2PrjCircle Include="
                  pr03.cwproj;
                  pr05.cwproj;
                  pr06.cwproj;
                  pr07.cwproj;
                  pr08.cwproj;
                  pr20.cwproj;
                  pr21.cwproj;
                  pr23.cwproj;
                  pr25.cwproj;
		             "/>
    </ItemGroup>
    <ItemGroup>
        <Pass3PrjEXE Include="
                  pr04.cwproj;
                  pr05exe.cwproj;
                  pr10.cwproj;
                  pr30.cwproj;
                  prCON.cwproj;
                  Gemini.cwproj;
                  RebuildEisPR.cwproj;
		          "/>
            <!--     PrCON.cwproj;    -->                
    </ItemGroup>

    <Target Name="Pass0BuildDLL">
        <MSBuild Projects="@(Pass0PrjDLL)"  
          Targets="Build" ContinueOnError="true" />  
    </Target>
    <Target Name="Pass1BuildDLL">
        <MSBuild Projects="@(Pass1PrjDLL)"  
          Targets="Build" ContinueOnError="true" />  
    </Target>
    <Target Name="Pass2BuildCircle">
        <MSBuild Projects="@(Pass2PrjCircle)"  
          Targets="Build" ContinueOnError="true" />  
    </Target>
    <Target Name="Pass3BuildEXE">
        <MSBuild Projects="@(Pass3PrjEXE)"  
          Targets="Build" ContinueOnError="true" />  
    </Target>
</Project>

00BldxSetClaVars.BAT file is Call by most BAT files here to set %Variables for Clarion IDE Paths. That way I can move to other machines where the IDE may not be in C:\Clarion

SET ClaBinPath=X:\Clarion11\bin
IF EXIST C:\Clarion11\bin SET ClaBinPath=C:\Clarion11\bin
IF EXIST D:\Clarion11\bin SET ClaBinPath=D:\Clarion11\bin

IF EXIST "%ClaBinPath%" GOTO :GotClaBP
  ECHO+
  ECHO ????????????????????????????????????????????????????????????
  ECHO ------------------------------------------------------------
  ECHO Clarion Path "%ClaBinPath%" does NOT exist
  ECHO ClarionCl.exe will fail.
  ECHO Edit "SET ClaBinPath=" in %0%
  ECHO ------------------------------------------------------------
  PAUSE
  GOTO :EndBadly
  
:GotClaBP
SET ClaClExe=%ClaBinPath%\ClarionCl.exe

IF EXIST "%ClaClExe%" GOTO :GotClaCL
  ECHO+
  ECHO ????????????????????????????????????????????????????????????
  ECHO ------------------------------------------------------------
  ECHO Clarion "%ClaClExe%" does NOT exist in "%ClaBinPath%"
  ECHO Check what's wrong in "SET ClaBinPath=" in %0%
  ECHO ------------------------------------------------------------
  PAUSE
  GOTO :EndBadly

:GotClaCL
GOTO :ExitBat
:EndBadly
:ExitBat
@REM cannot EXIT or CALL doesn't return

00Bld0Gen+Compile.BAT file drives the entire process of Generate and Build:

@REM Under Domain %~d0 & CD %~p0 set current drive & path to BAT Path
@%~d0
@CD %~p0
@Color 5e
@echo ==============================================================
@echo+ 
@echo Ready to Genarate using 00Bld1Generate.BAT
@echo then Compile using      00Bld2Compile.BAT
@echo+ 
@echo When done Log files will be opened in Notepad
@echo+ 
@echo+ 

@echo Pr00 and Pr01 tend to fail in this batch compile, so do you do again after.
@Echo Best for you to do BEFORE manually in IDE, then answer NO to below question.
@echo+ 
@Set BuildPassZero=Y
@CHOICE /C YN /M "????  Build Pr00 and Pr01 now in batch ??? "
@IF ERRORLEVEL 2 Set BuildPassZero=N
@IF (%BuildPassZero%)==(N) ECHO ..... Will Skip Building Pr00 and Pr01.  BuildPassZero=%BuildPassZero%

@echo+ 
@REM moved to CLean-->  @ECHO Delete QPR*.EXE QPR*.DLL QUSEREDIT.EXE to be re-compiled.
@REM moved to CLean-->  @DEL QPR*.EXE QPR*.DLL QUSEREDIT.EXE
@REM moved to CLean-->  @PAUSE

@DEL 00BuildGen.Log     > nul
@DEL 00BUILD_PASS.log   > nul
@DEL 00BUILD_Pass0.log  > nul
@DEL 00BUILD_Pass1.log  > nul
@DEL 00BUILD_Pass2.log  > nul
@DEL 00BUILD_Pass3.log  > nul
@DEL 00BUILD_ResultsEIS.log > nul

ECHO Results of build on %DATE% at %TIME% > 00BUILD_ResultsEIS.log
echo+ >> 00BUILD_ResultsEIS.log
echo Files before the Build >> 00BUILD_ResultsEIS.log
echo+ >> 00BUILD_ResultsEIS.log
@DIR Q*.DLL /on | Find "/" >> 00BUILD_ResultsEIS.log
@DIR *.EXE  /on | Find "/" >> 00BUILD_ResultsEIS.log


@REM Carl trying to debug Build wants to Skip Generate. The GOTO skips the question
@GOTO :YesGenerate
@CHOICE /C YN /M "???? Skip Generate APPs (i.e. answer Y to just Compile)"
@IF ERRORLEVEL 1 GOTO :NoGenerate
:YesGenerate
@TITLE Generate in %CD%
CALL 00Bld1Generate.BAT nostop
:NoGenerate

@TITLE Clean Exiting in %CD%
CALL 00Bld2Clean.BAT 
@TITLE Compile in %CD%
CALL 00Bld2Compile.BAT nostop
@TITLE Generate and Compile Complete in %CD%
ECHO+ >> 00BUILD_ResultsEIS.log
@echo ==============================================================                                >> 00BUILD_ResultsEIS.log
@IF NOT EXIST PrMsgBx.dll  ECHO ???? MISSING ???? PrMsgBx.dll  ?? File was NOT Built ??             >> 00BUILD_ResultsEIS.log
@IF NOT EXIST Qpr00.dll    ECHO ???? MISSING ???? Qpr00.dll    ?? File was NOT Built ??             >> 00BUILD_ResultsEIS.log
@IF NOT EXIST QPr01.dll    ECHO ???? MISSING ???? QPr01.dll    ?? File was NOT Built ??             >> 00BUILD_ResultsEIS.log
@IF NOT EXIST QPr02.dll    ECHO ???? MISSING ???? QPr02.dll    ?? File was NOT Built ??             >> 00BUILD_ResultsEIS.log
@IF NOT EXIST QPr03.dll    ECHO ???? MISSING ???? QPr03.dll    ?? File was NOT Built ??             >> 00BUILD_ResultsEIS.log
@IF NOT EXIST QPr06.dll    ECHO ???? MISSING ???? QPr06.dll    ?? File was NOT Built ??             >> 00BUILD_ResultsEIS.log
@IF NOT EXIST QPr07.dll    ECHO ???? MISSING ???? QPr07.dll    ?? File was NOT Built ??             >> 00BUILD_ResultsEIS.log
@IF NOT EXIST QPr08.dll    ECHO ???? MISSING ???? QPr08.dll    ?? File was NOT Built ??             >> 00BUILD_ResultsEIS.log
@IF NOT EXIST QPr20.dll    ECHO ???? MISSING ???? QPr20.dll    ?? File was NOT Built ??             >> 00BUILD_ResultsEIS.log
@IF NOT EXIST QPr21.dll    ECHO ???? MISSING ???? QPr21.dll    ?? File was NOT Built ??             >> 00BUILD_ResultsEIS.log
@IF NOT EXIST QPr22.dll    ECHO ???? MISSING ???? QPr22.dll    ?? File was NOT Built ??             >> 00BUILD_ResultsEIS.log
@IF NOT EXIST QPr23.dll    ECHO ???? MISSING ???? QPr23.dll    ?? File was NOT Built ??             >> 00BUILD_ResultsEIS.log
@IF NOT EXIST Qpr25.dll    ECHO ???? MISSING ???? Qpr25.dll    ?? File was NOT Built ??             >> 00BUILD_ResultsEIS.log
@IF NOT EXIST QPr04.exe    ECHO ???? MISSING ???? QPr04.exe    ?? File was NOT Built ??             >> 00BUILD_ResultsEIS.log
@IF NOT EXIST QPr05dll.dll ECHO ???? MISSING ???? QPr05dll.dll ?? File was NOT Built ?? Pr05.CwProj            >> 00BUILD_ResultsEIS.log
@IF NOT EXIST QPr05.exe    ECHO ???? MISSING ???? QPr05.exe    ?? File was NOT Built ?? Pr05exe.CwProj         >> 00BUILD_ResultsEIS.log
@IF NOT EXIST QPr10.exe    ECHO ???? MISSING ???? QPr10.exe    ?? File was NOT Built ??             >> 00BUILD_ResultsEIS.log
@IF NOT EXIST QPr30.exe    ECHO ???? MISSING ???? QPr30.exe    ?? File was NOT Built ??             >> 00BUILD_ResultsEIS.log
@IF NOT EXIST QPrCON.exe   ECHO ???? MISSING ???? QPrCON.exe   ?? File was NOT Built ??             >> 00BUILD_ResultsEIS.log
@IF NOT EXIST Gemini.exe   ECHO ???? MISSING ???? Gemini.exe   ?? File was NOT Built ??             >> 00BUILD_ResultsEIS.log
@IF NOT EXIST QUserEdit.exe ECHO ???? MISSING FILE ????  QUserEdit.exe ?? File was NOT Built ??     >> 00BUILD_ResultsEIS.log
@IF NOT EXIST QDoorEdit.exe ECHO ???? MISSING FILE ????  QDoorEdit.exe ?? File was NOT Built ??     >> 00BUILD_ResultsEIS.log
@echo ==============================================================                                >> 00BUILD_ResultsEIS.log
echo+ >> 00BUILD_ResultsEIS.log
echo Files after the Build >> 00BUILD_ResultsEIS.log
@DIR Q*.DLL /on | Find "/" >> 00BUILD_ResultsEIS.log
@DIR *.EXE  /on | Find "/" >> 00BUILD_ResultsEIS.log
echo+ >> 00BUILD_ResultsEIS.log
ECHO Build complete on %DATE% at %TIME% >> 00BUILD_ResultsEIS.log
START NOTEPAD.EXE 00BUILD_ResultsEIS.log
Color e5
@Echo+
@Echo Gen + Compile All Done. Review the Logs opened in Notepad.
@echo+
@Pause
DEL %0.bak

00Bld1Generate.BAT file generates the CLWE using ClarionCl.exe which is actually in a Call to 00BldxClarionCLGen1.BAT

@REM Under Domain %~d0 & CD %~p0 set current drive & path to BAT Path
@%~d0
@CD %~p0

@SET BldGenLog=00BuildGen.Log

@REM  @SET ClaBinPath=X:\Clarion10\bin
@REM  @IF EXIST C:\Clarion10\bin SET ClaBinPath=C:\Clarion10\bin
@REM  @IF EXIST D:\Clarion10\bin SET ClaBinPath=D:\Clarion10\bin
@REM  IF EXIST "%ClaBinPath%" GOTO :GotCla
@REM    ECHO Clarion Path "%ClaBinPath%" does NOT exist
@REM    ECHO ClarionCl.exe will fail. Edit "SET ClaBinPath=" in %0%
@REM    PAUSE
@REM    GOTO :EndBat
@REM  :GotCla

@CALL 00BldxSetClaVars.BAT
@IF NOT EXIST "%ClaBinPath%" GOTO :EndBat
SET ClaClExe=%ClaBinPath%\ClarionCl.exe
SET ClaGenCmd=%ClaClExe% -ag
@echo ==============================================================
@echo+ 
@echo Ready to Genarate all using %ClaGenCmd% %CD%\xxx.sln
@echo+
@IF (%1)==(nostop) GOTO :NoStop1 
@pause
:NoStop1
@echo Building all

Echo Generation in %CD% at %TIME% on %date% using %0   > %BldGenLog%

SET ClGenBat=00BldxClarionCLGen1.BAT
Echo Generate with CALL to %ClGenBat%

REM VerSontrol software is setting my APVs to ReadOnly so strip all those right now!
ATTRIB -R *.APV > nul

@rem in Alpha order because for generate should not matter

CALL %ClGenBat% PRMsgBx     %BldGenLog%
IF (%BuildPassZero%)==(N) GOTO :SkipZeroPass
CALL %ClGenBat% Pr00        %BldGenLog%
CALL %ClGenBat% Pr01        %BldGenLog%
:SkipZeroPass
CALL %ClGenBat% pr02        %BldGenLog%
CALL %ClGenBat% Pr03        %BldGenLog%
CALL %ClGenBat% pr04        %BldGenLog%
CALL %ClGenBat% pr05        %BldGenLog%
CALL %ClGenBat% pr05exe     %BldGenLog%
CALL %ClGenBat% pr06        %BldGenLog%
CALL %ClGenBat% pr07        %BldGenLog%
CALL %ClGenBat% pr08        %BldGenLog%
CALL %ClGenBat% pr10        %BldGenLog%
CALL %ClGenBat% pr20        %BldGenLog%
CALL %ClGenBat% pr21        %BldGenLog%
CALL %ClGenBat% pr22        %BldGenLog%
CALL %ClGenBat% pr23        %BldGenLog%
CALL %ClGenBat% pr25        %BldGenLog%
CALL %ClGenBat% pr30        %BldGenLog%
CALL %ClGenBat% prCON       %BldGenLog%
CALL %ClGenBat% Gemini      %BldGenLog%
CALL %ClGenBat% RebuildEisPR       %BldGenLog%

REM CALL %ClGenBat% useredit    %BldGenLog%

REM CALL %ClGenBat% PrCON       %BldGenLog%
REM PrCon raely changes so no need to be in Batch, plus it is likely to have errors if files changed

:AllDone 
ECHO ========================================== >> %BldGenLog%
ECHO All Done %TIME% >> %BldGenLog%
DIR *.APP    | Find /I ".APP"    >> %BldGenLog% 
ECHO+   >> %BldGenLog% 
DIR *.CWPROJ | Find /I ".CWPROJ" >> %BldGenLog% 

@echo --------------------------------------
start notepad.exe %BldGenLog%
@Echo+
@Echo All Done. Review the %BldGenLog% opened in Notepad.
@Echo If Gen was ok then run the BldCompile
@echo+
@IF (%1)==(nostop) GOTO :NoStop2
@Pause
:NoStop2
@REM DEL %0.bak
@REM DEL %ClGenBat%.BAK

00BldxClarionCLGen1.BAT file is called to run ClarionCl.exe for the passed APP

@REM was  00Bld1xClarionCLGen.BAT
@REM ren  00BldxClarionCLGen1.BAT
@REM Under Domain %~d0 & CD %~p0 set current drive & path to BAT Path
@%~d0
@CD %~p0
@TITLE Generate %1.APP in %CD%
@REM 5/23/17 changed from .APV to .APP since DecSys does not use APVs 

ECHO OFF
REM Pass %1=File Name w/o Extension  %2=LogFile
SET ApvSavePath=.\BldGenAppSave

@REM   SET ClaBinPath=X:\Clarion10\bin
@REM   IF EXIST C:\Clarion10\bin SET ClaBinPath=C:\Clarion10\bin
@REM   IF EXIST D:\Clarion10\bin SET ClaBinPath=D:\Clarion10\bin

IF EXIST "%ClaBinPath%" GOTO :GotCla
  ECHO Clarion Path "%ClaBinPath%" does NOT exist
  ECHO ClarionCl.exe will fail. Edit "SET ClaBinPath=" in %0%
  PAUSE
  GOTO :EndBadly
:GotCla
SET ClaClExe=%ClaBinPath%\ClarionCl.exe
SET ClaGenCmd=%ClaClExe% -ag

ECHO ================================== Generate %1 ==================================
ECHO ================================== Generate %1 ================================== %TIME% >> %2
ECHO Generate with: %0
ECHO Folder: %CD%
ECHO Solution: %1
ECHO LogFile:  %2
rem DIR %1.*
rem pause

IF NOT EXIST %1.sln ECHO Error SLN file does not exist %1.sln
IF NOT EXIST %1.sln GOTO :EndBadly

REM Save a Backup APV so can restore Date. Make sure and Del ApvSave incase orphan
IF NOT EXIST %ApvSavePath% MD %ApvSavePath%
REM do APP instead --> IF NOT EXIST %1.APV GOTO :NoApvFile
ECHO COPY %1.APP %ApvSavePath% - Save APP to restore date
IF EXIST %ApvSavePath%\%1.APP  del %ApvSavePath%\%1.APP
copy %1.APP %ApvSavePath% /v
IF ERRORLEVEL 1 PAUSE
IF ERRORLEVEL 1 GOTO :EndBadly
IF NOT EXIST %ApvSavePath% ECHO Unexpected! %1.SLN does not exist in %ApvSavePath%
IF NOT EXIST %ApvSavePath% GOTO :EndBadly
rem Attrib +R %1.apv  ClarionCL does not work if APV is RO so above made copy
:NoApvFile

REM Keep copy of SLN & CwProj with 
copy %1.CwProj %ApvSavePath%
rem copy %1.SLN %ApvSavePath%
REM Attrib +R %1.CwProj

DIR %1.APP | Find /I "%1.APP" >> %2 
@echo -------------------------------------- Gen Begin %TIME%
@echo+ 
@echo Generate %1 using %ClaGenCmd% %CD%\%1.sln
@echo Generate %1.sln >> %2
@echo          %ClaGenCmd% %CD%\%1.sln >> %2
@echo+ 
ATTRIB -R %1.APP
%ClaGenCmd% %CD%\%1.sln             >> %2
@REM ----- pause on error -----
@REM @ECHO ClarionCL returned ErrorLevel=%ErrorLevel% for %1.sln
@REM 03/09/20 saw this error: Error GENE000: The application C:\C11APPS\EisTrsTier2\Pr21.app cannot be load.
@IF NOT ERRORLEVEL 1 GOTO :NoErrz
@ECHO Error ???????????????????????????????????????????????????????????????????????
@ECHO ClarionCL returned ErrorLevel=%ErrorLevel% for %1.sln. 
@ECHO To see the error messages view the log file: %2
@ECHO Error ???????????????????????????????????????????????????????????????????????
PAUSE
:NoErrz
@REM ----- pause on error -----
ECHO Generation done  @  %TIME%     >> %2
@GOTO :SkipVerbose
DIR %1.APP    | Find /I "%1.APP"    >> %2 
DIR %1.CWPROJ | Find /I "%1.CWPROJ"    >> %2 
DIR %1.SLN    | Find /I "%1.SLN"    >> %2 
:SkipVerbose
@echo -------------------------------------- Gen Done %TIME%
rem pause
Attrib -R %1.CWPROJ

REM do App instead of -->  IF NOT EXIST %1.APV GOTO :NoApv2
REM --------- Copy APV back from %ApvSavePath% to restore date ----------
Echo After Generation copy APP backup to fix APP date
ECHO COPY %ApvSavePath%\%1.APP .\%1.APP - Restore APV from %ApvSavePath%
@REM ECHO Restore APP from %ApvSavePath% >> %2
copy %ApvSavePath%\%1.APP .\%1.APP
IF NOT ERRORLEVEL 1 GOTO :EndAOK
ECHO Error on restore APP from %ApvSavePath% - Level= %ErrorLevel% >> %2
ECHO Error on restore APP from %ApvSavePath% - Level= %ErrorLevel% 
pause
goto :EndBadly
:NoApv2

:EndAOK
@REM DIR %1.APP | Find /I "%1.APP" >> %2 
Echo Generation ended normally for %1.SLN
rem DIR %1.*
rem pause

GOTO :ExitBat

:EndBadly
ECHO ??????????????????? Generate %1 Ended BADLY? ??????????????????? >> %2
@ECHO+
@ECHO Ended Badly! Exiting Abnormally. Did not Generate %1.SLN
ECHO %1.APP in %CD%
DIR %1.APP | Find /I "%1.APP" >> %2
ECHO %1.APP in %ApvSavePath% 
DIR %ApvSavePath%\%1.APP | Find /I "%1.APP" >> %2
ECHO+
Pause
Attrib -R %1.*
GOTO :ExitBat

:ExitBat
@REM cannot EXIT or CALL doesn't return

00Bld2Compile.BAT file runs MSBuild

@REM Under Domain %~d0 & CD %~p0 set current drive & path to BAT Path
@%~d0
@CD %~p0

SET BldProj=00BldEisPayroll.msbuild
SET BldConfig=DEBUG

@REM   @SET ClaBinPath=X:\Clarion10\bin
@REM   @IF EXIST C:\Clarion10\bin SET ClaBinPath=C:\Clarion10\bin
@REM   @IF EXIST D:\Clarion10\bin SET ClaBinPath=D:\Clarion10\bin
@REM   @IF EXIST "%ClaBinPath%" GOTO :GotCla
@REM     ECHO Clarion Path "%ClaBinPath%" does NOT exist
@REM     ECHO MSBuild will fail. Edit "SET ClaBinPath=" in %0%
@REM     PAUSE
@REM     GOTO :EndBat
@REM   :GotCla

@CALL 00BldxSetClaVars.BAT
@IF NOT EXIST "%ClaBinPath%" GOTO :EndBat

SET BldSwitchz=/p:NoDependency="true" /p:CopyCoreFiles="true"

@echo off
@REM Other MSBuild switches of interest
@REM   /detailedsummary or /ds       Show detailed information at the end of the build log 
@REM   /verbosity:level or /v:level  Information to display in the build log. levels: q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic].

@IF EXIST "%BldProj%" GOTO :GotBPrj
  ECHO Build Project File "%BldProj%" does NOT exist
  ECHO MSBuild will fail. Edit "SET BldProj=" in %0%
  PAUSE
  GOTO :EndBat
:GotBPrj

REM Find Newsest MsBuild.Exe In Win\Microsoft.NET\Framework
SET MsBuildExe=%windir%\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe
IF Not Exist %MsBuildExe% SET MsBuildExe=%windir%\Microsoft.NET\Framework\v3.5\MSBuild.exe
IF Not Exist %MsBuildExe% SET MsBuildExe=%windir%\Microsoft.NET\Framework\v2.0.50727\MSBuild.exe
IF Not Exist %MsBuildExe% ECHO Did Not Find MSBuild in %MsBuildExe%
IF Not Exist %MsBuildExe% PAUSE
ECHO+
Echo =======================================================================
ECHO+
ECHO Ready to MSBuild %BldProj% as "%BldConfig%" using %ClaBinPath%
ECHO    Options:  %BldSwitch% 
ECHO    MSBuild: %MsBuildExe%
ECHO+ 
@IF (%1)==(nostop) GOTO :NoStop
@PAUSE
:NoStop
DEL 00BUILD_PASS.log    2> NUL
DEL 00BUILD_Pass0.log   2> NUL
DEL 00BUILD_Pass1.log   2> NUL
DEL 00BUILD_Pass2.log   2> NUL
DEL 00BUILD_Pass3.log   2> NUL
REM Write (echo) info to 00BUILD_PASS.log
Echo Build in %CD% at %TIME% on %date% using %0                           > 00BUILD_PASS.log
echo Project %BldProj% for "%BldConfig%"  using %ClaBinPath% %BldSwitch% >> 00BUILD_PASS.LOG
ECHO MSBuild.exe is %MsBuildExe%                                         >> 00BUILD_PASS.LOG
ECHO+                                         >> 00BUILD_PASS.LOG
ECHO The Build takes 3 passes: 1=DLLs; 2=DLL Circles; 3=EXEs.  Each pass has a Build LOG  >> 00BUILD_PASS.LOG
ECHO ******* Check the 1,2,3 Build_Pass#.LOG files at the bottom for "0 Errors" ********  >> 00BUILD_PASS.LOG
ECHO+                                         >> 00BUILD_PASS.LOG

IF (%BuildPassZero%)==(N) GOTO :SkipZeroPass
REM ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
@TITLE Compile Pass Zero (Problem APPs 00 and 01) in %CD%
@ECHO Pass0BuildDLL MSBuild %BldProj%
@SET Run1Bld=%MsBuildExe% %BldProj% /target:Pass0BuildDLL    /p:ClarionBinPath="%ClaBinPath%" /p:Configuration="%BldConfig%" %BldSwitchz%
@ECHO %Run1Bld% >> 00BUILD_PASS.LOG
%Run1Bld% >> 00BUILD_Pass0.log
start notepad.exe 00BUILD_Pass0.log
REM ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
:SkipZeroPass

@echo ON
REM   goto :pass3
@TITLE Compile Pass 1 of 3 in %CD%
@ECHO Pass1BuildDLL MSBuild %BldProj%
@SET Run1Bld=%MsBuildExe% %BldProj% /target:Pass1BuildDLL    /p:ClarionBinPath="%ClaBinPath%" /p:Configuration="%BldConfig%" %BldSwitchz%
@ECHO %Run1Bld% >> 00BUILD_PASS.LOG
%Run1Bld% >> 00BUILD_Pass1.log
start notepad.exe 00BUILD_Pass1.log

REM 07/13/20 use LibCreate_ImpLib.cwproj and can Skip2Pass ========================================
@ECHO Skip Pass 2 because of LibCreate_ImpLib.cwproj made LIBs >> 00BUILD_PASS.LOG
@ECHO Skip Pass 2 because of LibCreate_ImpLib.cwproj made LIBs >> 00BUILD_Pass2.log
@Dir *.LIB /on  >> 00BUILD_Pass2.log
GOTO :Skip2Pass

@SET Run2Bld=%MsBuildExe% %BldProj% /target:Pass2BuildCircle /p:ClarionBinPath="%ClaBinPath%" /p:Configuration="%BldConfig%" %BldSwitchz%
@TITLE Compile Pass 2 of 3 in %CD%
@ECHO %Run2Bld% >> 00BUILD_PASS.LOG
%Run2Bld% >> 00BUILD_Pass2.log
@start notepad.exe 00BUILD_Pass2.log

:Skip2Pass
REM 07/13/20  ========================================

:pass3
@SET Run3Bld=%MsBuildExe% %BldProj% /target:Pass3BuildEXE    /p:ClarionBinPath="%ClaBinPath%" /p:Configuration="%BldConfig%" %BldSwitchz%
@TITLE Compile Pass 3 of 3 in %CD%
@ECHO %Run3Bld% >> 00BUILD_PASS.LOG
%Run3Bld% >> 00BUILD_Pass3.log
@start notepad.exe 00BUILD_Pass3.log

@Echo+ >> 00BUILD_PASS.LOG
@Echo ======== Search for "Error" in LOG files ========================== >> 00BUILD_PASS.LOG
@FIND /I /N "error" 00BUILD_Pass1.log                >> 00BUILD_PASS.LOG
@FIND /I /N "error" 00BUILD_Pass2.log                >> 00BUILD_PASS.LOG
@FIND /I /N "error" 00BUILD_Pass3.log                >> 00BUILD_PASS.LOG
@Echo =================================================================== >> 00BUILD_PASS.LOG

@ECHO ===================================== Done %TIME% %DATE% >> 00BUILD_PASS.log
@ECHO --- DLL Files: (by Date) ---  >> 00BUILD_PASS.log
@DIR *.dll /odn | Find /I ".DLL"    >> 00BUILD_PASS.log
@ECHO+                              >> 00BUILD_PASS.log
@ECHO --- EXE Files: (by Date) ---  >> 00BUILD_PASS.log
@DIR *.exe /odn | Find /I ".EXE"    >> 00BUILD_PASS.log

@start notepad.exe 00BUILD_Pass.log
@Echo OFF
Echo+
Echo Builds done, check 00BUILD_Pass*.log files
@IF (%1)==(nostop) GOTO :EndBat
Pause
:EndBat
@REM DEL %0.bak

00Bld2Clean.BAT file is called at the start to delete all the DLL and EXE files in the project:

@REM Under Domain %~d0 & CD %~p0 set current drive & path to BAT Path
@%~d0
@CD %~p0

Echo Clean EXE and DLL in %CD% at %TIME% on %date% using %0  

DEL PrMsgBx.dll
IF (%BuildPassZero%)==(N) GOTO :SkipZeroPass
DEL Qpr00.dll
DEL QPr01.dll
:SkipZeroPass
DEL QPr02.dll
DEL QPr03.dll
DEL QPr05dll.dll
DEL QPr06.dll
DEL QPr07.dll
DEL QPr08.dll
DEL QPr20.dll
DEL QPr21.dll
DEL QPr22.dll
DEL QPr23.dll
DEL Qpr25.dll

DEL QPr04.exe
DEL QPr05.exe
DEL QPr10.exe
DEL QPr30.exe
DEL QPrCON.exe
DEL Gemini.exe
DEL RebuildEisPR.EXE

REM DEL qDoorEdit.exe
REM DEL qUSEREDIT.exe

DEL WinPreview????????-*.exe

@REM DEL %0.bak

LibCreate_ImpLib_prj.pr file was created using the BAT in my post above. This generates the LIBs from the generated EXPs for the Build can be done in one pass:

#noedit    
-- #implib xxx.LIB xxx.EXP 

#implib PRMSGBX.LIB PRMSGBX.EXP 
-- #implib QPR00.LIB QPR00.EXP 
-- #implib QPR01.LIB QPR01.EXP 
#implib QPR02.LIB QPR02.EXP 
#implib QPR03.LIB QPR03.EXP 
#implib QPR06.LIB QPR06.EXP 
#implib QPR07.LIB QPR07.EXP 
#implib QPR08.LIB QPR08.EXP 
#implib QPR20.LIB QPR20.EXP 
#implib QPR21.LIB QPR21.EXP 
#implib QPR22.LIB QPR22.EXP 
#implib QPR23.LIB QPR23.EXP 
#implib QPR25.LIB QPR25.EXP 

LibCreate_ImpLib.cwproj is a simple Project to Include=ā€œLibCreate_ImpLib_prj.prā€ to run #ImpLib. Don’t make this as XML, just add a simple Win EXE project and add the PR file.

<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <ProjectGuid>{396CA655-F1DB-47AE-AD97-463EB809F3D0}</ProjectGuid>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">Win32</Platform>
    <OutputType>Module</OutputType>
    <RootNamespace>LibCreate_ImpLib</RootNamespace>
    <AssemblyName>LibCreate_ImpLib</AssemblyName>
    <RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
    <Model>Dll</Model>
    <DefineConstants>maincode=&gt;on</DefineConstants>
    <stack_size>16384</stack_size>
    <CopyCore>True</CopyCore>
    <OutputName>LibCreate_ImpLib</OutputName>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
    <DebugSymbols>True</DebugSymbols>
    <DebugType>Full</DebugType>
    <vid>full</vid>
    <check_stack>True</check_stack>
    <check_index>True</check_index>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
    <DebugSymbols>False</DebugSymbols>
    <DebugType>None</DebugType>
    <vid>off</vid>
    <check_stack>False</check_stack>
    <check_index>False</check_index>
    <warnings>on</warnings>
    <GenerateMap>True</GenerateMap>
    <line_numbers>False</line_numbers>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="LibCreate_ImpLib.clw" />
  </ItemGroup>
  <ItemGroup>
    <Include Include="LibCreate_ImpLib_prj.pr" />
  </ItemGroup>
  <Import Project="$(ClarionBinPath)\SoftVelocity.Build.Clarion.targets" />
  <PropertyGroup>
    <PostBuildEvent>DEL LibCreate_ImpLib.LIB</PostBuildEvent>
  </PropertyGroup>
</Project>

LibCreate_ImpLib.clw file is used in the above project that must exist but does nothing:

!Open LibCreate_ImpLib.PR under "Projects to Include" to see what this is really doing
!This makes the Import .LIBs from the .EXPs for this project. Just build this, it will NOT run
!Insert this project first in your bulk compile so all your LIBs are correct and you have no missing externals

  PROGRAM
!  MAP.
  CODE

  !Based on https://clarionmag.jira.com/wiki/spaces/clarion/pages/399918/Handling+circular+references+with+implib  
  !
  !The TopSpeed / Clarion Project Laanguage is described in the AdvancedTopicsReferenceGuide.pdf
  !  Note this is WRONG syntax: #implib <ExpFilename> <LibFilename>  
  !           The Right Syntax: #implib <LibFilename> <ExpFilename>  
  !  Search #implib finds all examples with the right syntax: #implib %%drvname%%.lib %%drvname%%.exp
  
!This SLN under "Projects to Include" has LibCreate_ImpLib.PR Project file with lines like below that make the LIBs.
!-------------------------------------------------
!    -- no need #implib ALLFILES.LIB  ALLFILES.EXP  -- no need to do first file built with no imports
!    #implib REPORTS.LIB   REPORTS.EXP
!    #implib UPDATES.LIB   UPDATES.EXP 
!-------------------------------------------------
!Each line of the prj is simply an #implib statement followed by the name of the LIB to be created and the EXP to use when creating the LIB.
!
!So while this CLW has no code that does anything, it is set to create a LIB that can be disposed
!So ths CwProj has Post Build Event to:  DEL LibCreate_ImpLib.LIB
!If this makes an EXE then: DEL LibCreate_ImpLib.EXE & LibCreate_ImpLib.LIB
!
!Created by Carl Barnes based on Dave Harms article and posts. Thanks you Dave! I also recall Gordon Smith recommending #implib.
      

Thanks!

Claude is helping me figure out the errors.

Will look this over.

Peter
[phone number removed for privacy – please use PM]

Carl,

Thanks for this, but my problem is more basic than that.

Claude showed me how to call MSBuild, and that works.
On each round, MSBuild is showing me the first missing GUID.
KSS cannot find any sln that contains that build number.
So, I figure I’m stuck.
That is, I cannot build the multi-dll sln if I cannot find which projs
are missing.
That’s why I wanted to build a batch file with all the slns.
A Clarion program reads the directory, filters the slns that I need,
writes a batch file.
Shouldn’t that work?

I’d appreciate your thoughts.

Thanks again,
Peter

It’d help if you showed us what you already have? I might not be on the right track, but this is a batch file that I used a long time ago to build and compile a large collection of app. Did you say you are not sure what apps actually constitute your application? That could make it hard. Can you just start with all the apps in your app folder?

@ECHO OFF
FOR %%x IN (data firstapp secondapp thirdapp etc app extension is added for you) DO C:\Clarion91\BIN\clarionCL -ConfigDir C:\Clarion91\Bin\Settings /win /agc OFF /ag c:\YourAppFolder\p_%%x.app
C:\Clarion91\BIN\clarionCL  -ConfigDir C:\Clarion91\Bin\Settings /win /agc OFF /ag c:\YourAppFolder\YourApp.app

ECHO Build completed - starting compile

:: Now compile obj, lib and dlls
%windir%\Microsoft.NET\Framework\v2.0.50727\MSBuild _master.msbuild /nologo /p:ClarionBinPath="c:\Clarion91\bin" /p:NoDependency="true" /p:Configuration="Release" /p:CopyCoreFiles="true" /p:ConfigDir="C:\Clarion91\Bin\Settings" /target:First > _build_first.log 

:: Compile again because of circular dependencies
%windir%\Microsoft.NET\Framework\v2.0.50727\MSBuild _master.msbuild /nologo /p:ClarionBinPath="c:\Clarion91\bin" /p:NoDependency="true" /p:Configuration="Release" /p:CopyCoreFiles="true" /p:ConfigDir="C:\Clarion91\Bin\Settings" /target:Second > _build_second.log 

ECHO Compile Completed 
 
PAUSE