1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

Patch for Sean Evoy

In order to meet certain internal guidelines and to test the makefile 
generator, the build model replied to some answers with hard-coded 
information. This patch moves the information into the build model. Tests 
have been updated to reflect these changes, and the patch has been 
smoke-tested on Unix.
This commit is contained in:
John Camelon 2003-07-29 14:28:40 +00:00
parent 5423bbc79e
commit ae3a1417f5
12 changed files with 269 additions and 70 deletions

View file

@ -20,6 +20,20 @@
2003-07-28 John Camelon 2003-07-28 John Camelon
Added/moved tests as necessary for bugfix 40842 & 40843. Added/moved tests as necessary for bugfix 40842 & 40843.
2003-07-28 Sean Evoy
In order to meet certain internal guidelines and to test the makefile
generator, the build model replied to some answers with hard-coded information.
This patch moves the information into the build model.
* plugin.xml:
Added information to the target tags to test inheritence and
overridding the make command and clean command attributes.
* build/org/eclipse/cdt/core/build/managed/tests/AllBuildTests.java:
Added code to test the make command and clean command attributes in
Targets. Also added a test to insure that sub-sub targets inherit settings
properly.
2003-07-28 Andrew Niefer 2003-07-28 Andrew Niefer
This patch creates a new failing test class : FullParseFailedTests. This This patch creates a new failing test class : FullParseFailedTests. This
is for writing failed tests on the parser doing COMPLETE_PARSE. is for writing failed tests on the parser doing COMPLETE_PARSE.

View file

@ -74,6 +74,7 @@ public class AllBuildTests extends TestCase {
public void testExtensions() throws Exception { public void testExtensions() throws Exception {
ITarget testRoot = null; ITarget testRoot = null;
ITarget testSub = null; ITarget testSub = null;
ITarget testSubSub = null;
// Note secret null parameter which means just extensions // Note secret null parameter which means just extensions
ITarget[] targets = ManagedBuildManager.getDefinedTargets(null); ITarget[] targets = ManagedBuildManager.getDefinedTargets(null);
@ -84,17 +85,22 @@ public class AllBuildTests extends TestCase {
if (target.getName().equals("Test Root")) { if (target.getName().equals("Test Root")) {
testRoot = target; testRoot = target;
checkRootTarget(testRoot, "x"); checkRootTarget(testRoot, "x");
} else if (target.getName().equals("Test Sub")) { } else if (target.getName().equals("Test Sub")) {
testSub = target; testSub = target;
checkSubTarget(testSub); checkSubTarget(testSub);
} else if (target.getName().equals("Test Sub Sub")) {
testSubSub = target;
checkSubSubTarget(testSubSub);
} }
} }
// All these targets are defines in the plugin files, so none
// of them should be null at this point
assertNotNull(testRoot); assertNotNull(testRoot);
assertNotNull(testSub); assertNotNull(testSub);
assertNotNull(testSubSub);
} }
/** /**
* The purpose of this test is to exercise the build path info interface. * The purpose of this test is to exercise the build path info interface.
* To get to that point, a new target/config has to be created in the test * To get to that point, a new target/config has to be created in the test
@ -465,8 +471,12 @@ public class AllBuildTests extends TestCase {
*/ */
private void checkRootTarget(ITarget target, String oicValue) throws BuildException { private void checkRootTarget(ITarget target, String oicValue) throws BuildException {
// Target stuff // Target stuff
String expectedCleanCmd = "del /myworld";
String expectedMakeCommand = "make";
assertTrue(target.isTestTarget()); assertTrue(target.isTestTarget());
assertEquals(target.getDefaultExtension(), rootExt); assertEquals(target.getDefaultExtension(), rootExt);
assertEquals(expectedCleanCmd, target.getCleanCommand());
assertEquals(expectedMakeCommand, target.getMakeCommand());
// Tools // Tools
ITool[] tools = target.getTools(); ITool[] tools = target.getTools();
@ -570,6 +580,16 @@ public class AllBuildTests extends TestCase {
assertEquals("doIt", tools[0].getToolCommand()); assertEquals("doIt", tools[0].getToolCommand());
} }
/**
* @param testSubSub
*/
private void checkSubSubTarget(ITarget target) {
// Check the inherited clean command
assertEquals("rm -yourworld", target.getCleanCommand());
assertEquals("nmake", target.getMakeCommand());
}
/* /*
* Do a sanity check on the values in the sub-target. Most of the * Do a sanity check on the values in the sub-target. Most of the
* sanity on the how build model entries are read is performed in * sanity on the how build model entries are read is performed in
@ -578,6 +598,10 @@ public class AllBuildTests extends TestCase {
* in the sub target, the test does a sanity check just to be complete. * in the sub target, the test does a sanity check just to be complete.
*/ */
private void checkSubTarget(ITarget target) throws BuildException { private void checkSubTarget(ITarget target) throws BuildException {
// Check the overridden clan command
assertEquals("rm -yourworld", target.getCleanCommand());
assertEquals("gmake", target.getMakeCommand());
// Make sure this is a test target // Make sure this is a test target
assertTrue(target.isTestTarget()); assertTrue(target.isTestTarget());
// Make sure the build artifact extension is there // Make sure the build artifact extension is there

View file

@ -27,10 +27,13 @@
name="Tools for Build Test" name="Tools for Build Test"
point="org.eclipse.cdt.core.ManagedBuildInfo"> point="org.eclipse.cdt.core.ManagedBuildInfo">
<target <target
makeFlags="-k"
isTest="true" isTest="true"
cleanCommand="del /myworld"
name="Test Root" name="Test Root"
defaultExtension="toor" defaultExtension="toor"
isAbstract="false" isAbstract="false"
makeCommand="make"
id="test.root"> id="test.root">
<tool <tool
sources="foo,bar" sources="foo,bar"
@ -109,12 +112,15 @@
</configuration> </configuration>
</target> </target>
<target <target
isTest="true"
name="Test Sub" name="Test Sub"
parent="test.root" id="test.sub"
cleanCommand="rm -yourworld"
isTest="true"
defaultExtension="bus" defaultExtension="bus"
isAbstract="false" isAbstract="false"
id="test.sub"> makeCommand="gmake"
makeFlags="-d"
parent="test.root">
<configuration <configuration
name="Sub Config" name="Sub Config"
id="sub.config"> id="sub.config">
@ -122,8 +128,8 @@
<tool <tool
sources="yarf" sources="yarf"
name="Sub Tool" name="Sub Tool"
outputPrefix="lib"
outputs="bus" outputs="bus"
outputPrefix="lib"
id="tool.sub"> id="tool.sub">
<option <option
name="Include Paths" name="Include Paths"
@ -154,6 +160,14 @@
</option> </option>
</tool> </tool>
</target> </target>
<target
isTest="true"
name="Test Sub Sub"
parent="test.sub"
defaultExtension="tss"
makeCommand="nmake"
id="test.sub.sub">
</target>
</extension> </extension>
</plugin> </plugin>

View file

@ -1,3 +1,24 @@
2003-07-28 Sean Evoy
In order to meet certain internal guidelines and to test the makefile
generator, the build model replied to some answers with hard-coded information.
This patch moves the information into the build model.
* schema/ManagedBuildTools.exsd
* build/org/eclipse/cdt/core/build/managed/ITarget.java
* build/org/eclipse/cdt/internal/core/build/managed/Target.java
* build/org/eclipse/cdt/internal/core/build/managed/ManagedBuildInfo.java:
Added code to correctly extract and persist the make command and clean
command from a Target/ITarget. Added the attributes to the schema. Removed
the hard-coded answers from the ManagedBuildManager.
* src/org/eclipse/cdt/internal/core/GeneratedMakefileBuilder.java:
Removed two methods that were no longer invoked from the builder.
* src/org/eclipse/cdt/internal/core/MakefileGenerator.java:
Corrected a bug in the makefile generator whereby the output prefix was applied
twice to library targets, i.e. liblibfoo.a instead of libfoo.a.
2003-07-24 Sean Evoy 2003-07-24 Sean Evoy
* src/org/eclipse/cdt/internal/core/MakefileGenerator.java: * src/org/eclipse/cdt/internal/core/MakefileGenerator.java:
Added code to place interproject dependencies in target build rule, Added code to place interproject dependencies in target build rule,

View file

@ -46,6 +46,13 @@ public interface ITarget extends IBuildObject {
*/ */
public String getArtifactName(); public String getArtifactName();
/**
* Answers the OS-specific command to remove files created by the build
*
* @return
*/
public String getCleanCommand();
/** /**
* Returns all of the configurations defined by this target. * Returns all of the configurations defined by this target.
* @return * @return
@ -60,6 +67,13 @@ public interface ITarget extends IBuildObject {
*/ */
public String getDefaultExtension(); public String getDefaultExtension();
/**
* Answers the name of the make utility for the target.
*
* @return
*/
public String getMakeCommand();
/** /**
* Returns the configuration with the given id, or null if not found. * Returns the configuration with the given id, or null if not found.
* *
@ -111,4 +125,5 @@ public interface ITarget extends IBuildObject {
*/ */
public void setBuildArtifact(String name); public void setBuildArtifact(String name);
} }

View file

@ -116,8 +116,11 @@ public class ManagedBuildInfo implements IManagedBuildInfo, IScannerInfo {
* @see org.eclipse.cdt.core.build.managed.IManagedBuildInfo#getCleanCommand() * @see org.eclipse.cdt.core.build.managed.IManagedBuildInfo#getCleanCommand()
*/ */
public String getCleanCommand() { public String getCleanCommand() {
// TODO Get from the model // Get from the model
return new String("rm -rf"); String command = new String();
ITarget target = getDefaultTarget();
command = target.getCleanCommand();
return command;
} }
/* (non-Javadoc) /* (non-Javadoc)
@ -276,8 +279,10 @@ public class ManagedBuildInfo implements IManagedBuildInfo, IScannerInfo {
* @see org.eclipse.cdt.core.build.managed.IManagedBuildInfo#getMakeCommand() * @see org.eclipse.cdt.core.build.managed.IManagedBuildInfo#getMakeCommand()
*/ */
public String getMakeCommand() { public String getMakeCommand() {
// TODO Don't hard-code this String command = new String();
return new String("make"); ITarget target = getDefaultTarget();
command = target.getMakeCommand();
return command;
} }
/* (non-Javadoc) /* (non-Javadoc)

View file

@ -31,16 +31,18 @@ import org.w3c.dom.Node;
*/ */
public class Target extends BuildObject implements ITarget { public class Target extends BuildObject implements ITarget {
private ITarget parent; private String artifactName;
private IResource owner; private String cleanCommand;
private List tools;
private Map toolMap;
private List configurations;
private Map configMap; private Map configMap;
private List configurations;
private String defaultExtension;
private boolean isAbstract = false; private boolean isAbstract = false;
private boolean isTest = false; private boolean isTest = false;
private String artifactName; private String makeCommand;
private String defaultExtension; private IResource owner;
private ITarget parent;
private Map toolMap;
private List tools;
private static final IConfiguration[] emptyConfigs = new IConfiguration[0]; private static final IConfiguration[] emptyConfigs = new IConfiguration[0];
private static final String EMPTY_STRING = new String(); private static final String EMPTY_STRING = new String();
@ -66,6 +68,8 @@ public class Target extends BuildObject implements ITarget {
this.artifactName = parent.getArtifactName(); this.artifactName = parent.getArtifactName();
this.defaultExtension = parent.getDefaultExtension(); this.defaultExtension = parent.getDefaultExtension();
this.isTest = parent.isTestTarget(); this.isTest = parent.isTestTarget();
this.cleanCommand = parent.getCleanCommand();
this.makeCommand = parent.getMakeCommand();
// Hook me up // Hook me up
IManagedBuildInfo buildInfo = ManagedBuildManager.getBuildInfo(owner, true); IManagedBuildInfo buildInfo = ManagedBuildManager.getBuildInfo(owner, true);
@ -111,6 +115,20 @@ public class Target extends BuildObject implements ITarget {
// Is this a test target // Is this a test target
isTest = ("true".equals(element.getAttribute("isTest"))); isTest = ("true".equals(element.getAttribute("isTest")));
// Get the clean command
cleanCommand = element.getAttribute("cleanCommand");
if (cleanCommand == null) {
// See if it defined in the parent
cleanCommand = parent.getCleanCommand();
}
// Get the make command
makeCommand = element.getAttribute("makeCommand");
if (makeCommand == null) {
// See if it defined in the parent
makeCommand = parent.getMakeCommand();
}
IConfigurationElement[] targetElements = element.getChildren(); IConfigurationElement[] targetElements = element.getChildren();
for (int k = 0; k < targetElements.length; ++k) { for (int k = 0; k < targetElements.length; ++k) {
IConfigurationElement targetElement = targetElements[k]; IConfigurationElement targetElement = targetElements[k];
@ -160,6 +178,12 @@ public class Target extends BuildObject implements ITarget {
// Is this a test target // Is this a test target
isTest = ("true".equals(element.getAttribute("isTest"))); isTest = ("true".equals(element.getAttribute("isTest")));
// Get the clean command
cleanCommand = element.getAttribute("cleanCommand");
// Get the make command
makeCommand = element.getAttribute("makeCommand");
Node child = element.getFirstChild(); Node child = element.getFirstChild();
while (child != null) { while (child != null) {
if (child.getNodeName().equals("configuration")) { if (child.getNodeName().equals("configuration")) {
@ -184,6 +208,8 @@ public class Target extends BuildObject implements ITarget {
element.setAttribute("artifactName", getArtifactName()); element.setAttribute("artifactName", getArtifactName());
element.setAttribute("defaultExtension", getDefaultExtension()); element.setAttribute("defaultExtension", getDefaultExtension());
element.setAttribute("isTest", isTest ? "true" : "false"); element.setAttribute("isTest", isTest ? "true" : "false");
element.setAttribute("cleanCommand", getCleanCommand());
element.setAttribute("makeCommand", getMakeCommand());
if (configurations != null) if (configurations != null)
for (int i = 0; i < configurations.size(); ++i) { for (int i = 0; i < configurations.size(); ++i) {
@ -194,6 +220,14 @@ public class Target extends BuildObject implements ITarget {
} }
} }
/* (non-Javadoc)
* @see org.eclipse.cdt.core.build.managed.ITarget#getMakeCommand()
*/
public String getMakeCommand() {
// Return the name of the make utility
return makeCommand == null ? EMPTY_STRING : makeCommand;
}
public String getName() { public String getName() {
return (name == null && parent != null) ? parent.getName() : name; return (name == null && parent != null) ? parent.getName() : name;
} }
@ -267,6 +301,14 @@ public class Target extends BuildObject implements ITarget {
return defaultExtension == null ? EMPTY_STRING : defaultExtension; return defaultExtension == null ? EMPTY_STRING : defaultExtension;
} }
/* (non-Javadoc)
* @see org.eclipse.cdt.core.build.managed.ITarget#getCleanCommand()
*/
public String getCleanCommand() {
// Return the command used to remove files
return cleanCommand == null ? EMPTY_STRING : cleanCommand;
}
/* (non-Javadoc) /* (non-Javadoc)
* @see org.eclipse.cdt.core.build.managed.ITarget#getArtifactName() * @see org.eclipse.cdt.core.build.managed.ITarget#getArtifactName()
*/ */
@ -325,4 +367,5 @@ public class Target extends BuildObject implements ITarget {
public void setBuildArtifact(String name) { public void setBuildArtifact(String name) {
artifactName = name; artifactName = name;
} }
} }

View file

@ -358,6 +358,27 @@ Two additional types exist to flag options of special relevance to the build mod
</documentation> </documentation>
</annotation> </annotation>
</attribute> </attribute>
<attribute name="cleanCommand" type="string">
<annotation>
<documentation>
This attribute maintains the command that removes files for a particular target. For example, on POSIX targets like Linuc, Solaris, or Cygwin, the command would be &lt;code&gt;rm -rf&lt;/code&gt; whereas on Win32 platforms it would be &lt;code&gt;del /F /S /Q&lt;/code&gt;
</documentation>
</annotation>
</attribute>
<attribute name="makeCommand" type="string">
<annotation>
<documentation>
</documentation>
</annotation>
</attribute>
<attribute name="makeFlags" type="string">
<annotation>
<documentation>
</documentation>
</annotation>
</attribute>
</complexType> </complexType>
</element> </element>

View file

@ -11,7 +11,6 @@ package org.eclipse.cdt.internal.core;
* IBM Rational Software - Initial API and implementation * IBM Rational Software - Initial API and implementation
* **********************************************************************/ * **********************************************************************/
import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
@ -31,16 +30,12 @@ import org.eclipse.cdt.core.model.ICModelMarker;
import org.eclipse.cdt.core.resources.ACBuilder; import org.eclipse.cdt.core.resources.ACBuilder;
import org.eclipse.cdt.core.resources.IConsole; import org.eclipse.cdt.core.resources.IConsole;
import org.eclipse.cdt.core.resources.MakeUtil; import org.eclipse.cdt.core.resources.MakeUtil;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor; import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IResourceStatus;
import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.IncrementalProjectBuilder; import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IPath;
@ -195,51 +190,6 @@ public class GeneratedMakefileBuilder extends ACBuilder {
monitor.worked(1); monitor.worked(1);
} }
protected IPath getBuildDirectory(String dirName) throws CoreException {
// Create or get the handle for the build directory
IFolder folder = getProject().getFolder(dirName);
if (!folder.exists()) {
try {
folder.create(false, true, null);
}
catch (CoreException e) {
if (e.getStatus().getCode() == IResourceStatus.PATH_OCCUPIED)
folder.refreshLocal(IResource.DEPTH_ZERO, null);
else
throw e;
}
}
return folder.getFullPath();
}
/**
* Gets the makefile for the project. It may be empty.
*
* @return The <code>IFile</code> to generate the makefile into.
*/
protected IFile getMakefile(IPath filePath, IProgressMonitor monitor) throws CoreException {
// Create or get the handle for the makefile
IWorkspaceRoot root = CCorePlugin.getWorkspace().getRoot();
IFile newFile = root.getFileForLocation(filePath);
if (newFile == null) {
newFile = root.getFile(filePath);
}
// Create the file if it does not exist
ByteArrayInputStream contents = new ByteArrayInputStream(new byte[0]);
try {
newFile.create(contents, false, monitor);
}
catch (CoreException e) {
// If the file already existed locally, just refresh to get contents
if (e.getStatus().getCode() == IResourceStatus.PATH_OCCUPIED)
newFile.refreshLocal(IResource.DEPTH_ZERO, null);
else
throw e;
}
// TODO handle long running file operation
return newFile;
}
/** /**
* @param makefilePath * @param makefilePath
* @param info * @param info

View file

@ -298,7 +298,7 @@ public class MakefileGenerator {
* <cd <Proj_Dep_1/build_dir>; make all> * <cd <Proj_Dep_1/build_dir>; make all>
* <cd <Proj_Dep_.../build_dir>; make all> * <cd <Proj_Dep_.../build_dir>; make all>
* <cd <Proj_Dep_n/build_dir>; make all> * <cd <Proj_Dep_n/build_dir>; make all>
* $(BUILD_TOOL) $(FLAGS) $(OUTPUT_FLAG) $(OUTPUT_PREFIX)$@ $^ $(LIB_DEPS) * $(BUILD_TOOL) $(FLAGS) $(OUTPUT_FLAG) $@ $^ $(LIB_DEPS)
*/ */
String cmd = info.getToolForTarget(extension); String cmd = info.getToolForTarget(extension);
String flags = info.getFlagsForTarget(extension); String flags = info.getFlagsForTarget(extension);
@ -323,7 +323,7 @@ public class MakefileGenerator {
e.printStackTrace(); e.printStackTrace();
} }
buffer.append(TAB + cmd + WHITESPACE + flags + WHITESPACE + outflag + WHITESPACE + outputPrefix + "$@" + WHITESPACE + "$^"); buffer.append(TAB + cmd + WHITESPACE + flags + WHITESPACE + outflag + WHITESPACE + "$@" + WHITESPACE + "$^");
String[] libraries = info.getLibsForTarget(extension); String[] libraries = info.getLibsForTarget(extension);
for (int i = 0; i < libraries.length; i++) { for (int i = 0; i < libraries.length; i++) {
String lib = libraries[i]; String lib = libraries[i];

View file

@ -1,3 +1,13 @@
2003-07-28 Sean Evoy
In order to meet certain internal guidelines and to test the makefile
generator, the build model replied to some answers with hard-coded information.
This patch moves the information into the build model.
* plugin.xml:
Added new attributes to Targets to add make command, clean command and
make flag information. I also added a toolchain specification for Solaris, but
it is turned off for now until I test it.
2003-07-24 Sean Evoy 2003-07-24 Sean Evoy
* plugin.xml: * plugin.xml:
Added new attributes to tools and changed the value type enum for Added new attributes to tools and changed the value type enum for

View file

@ -621,9 +621,12 @@
name="Managed Build Tools Description" name="Managed Build Tools Description"
point="org.eclipse.cdt.core.ManagedBuildInfo"> point="org.eclipse.cdt.core.ManagedBuildInfo">
<target <target
makeFlags="-k"
isTest="false" isTest="false"
cleanCommand="rm -rf"
name="Cygwin" name="Cygwin"
isAbstract="true" isAbstract="true"
makeCommand="make"
id="cygwin"> id="cygwin">
<tool <tool
sources="c,cc,cpp,cxx,C" sources="c,cc,cpp,cxx,C"
@ -888,9 +891,12 @@
</tool> </tool>
</target> </target>
<target <target
makeFlags="-k"
isTest="true" isTest="true"
cleanCommand="rm -rf"
name="Linux" name="Linux"
isAbstract="true" isAbstract="true"
makeCommand="make"
id="linux"> id="linux">
<tool <tool
name="Compiler" name="Compiler"
@ -960,6 +966,82 @@
id="org.eclipse.cdt.ui.tests.tool.linux.ar"> id="org.eclipse.cdt.ui.tests.tool.linux.ar">
</tool> </tool>
</target> </target>
<target
makeFlags="-k"
isTest="true"
cleanCommand="rm -rf"
name="Solaris"
isAbstract="true"
makeCommand="make"
id="solaris">
<tool
name="Compiler"
outputFlag="-o"
id="solaris.compiler">
<optionCategory
owner="solaris.compiler"
name="Optimization Options"
id="solaris.compiler.optimization">
</optionCategory>
<option
name="Compiler Flags"
valueType="string"
id="solaris.compiler.flags">
</option>
<option
name="Optimization Flags"
category="solaris.compiler.optimization"
value="-O"
valueType="string"
id="solaris.compiler.optimizationFlags">
</option>
</tool>
</target>
<target
isTest="true"
name="Solaris Executable"
parent="solaris"
isAbstract="false"
id="solaris.exec">
<tool
name="Linker"
outputFlag="-o"
id="solaris.link">
</tool>
<configuration
name="Release"
id="Solaris.exec.release">
</configuration>
<configuration
name="Debug"
id="solaris.exec.debug">
</configuration>
</target>
<target
isTest="true"
name="Solaris Shared Library"
parent="solaris"
defaultExtension=".so"
isAbstract="false"
id="solaris.so">
<tool
name="Linker"
outputFlag="-o"
id="solaris.solink">
</tool>
</target>
<target
isTest="true"
name="Solaris Static Library"
parent="solaris"
defaultExtension=".a"
isAbstract="false"
id="solaris.lib">
<tool
name="Archiver"
id="solaris.ar">
</tool>
</target>
</extension> </extension>
<extension <extension
id="org.eclipse.cdt.ui.CSearchPage" id="org.eclipse.cdt.ui.CSearchPage"