00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "CellMLToSharedLibraryConverter.hpp"
00030
00031 #include <sstream>
00032 #include <unistd.h>
00033 #include <sys/stat.h>
00034 #include <ctime>
00035
00036 #include "Exception.hpp"
00037 #include "ChasteBuildRoot.hpp"
00038 #include "PetscTools.hpp"
00039 #include "DynamicModelLoaderRegistry.hpp"
00040 #include "GetCurrentWorkingDirectory.hpp"
00041
00042 CellMLToSharedLibraryConverter::CellMLToSharedLibraryConverter(bool preserveGeneratedSources,
00043 std::string component)
00044 : mPreserveGeneratedSources(preserveGeneratedSources),
00045 mComponentName(component)
00046 {
00047 }
00048
00049 DynamicCellModelLoader* CellMLToSharedLibraryConverter::Convert(const FileFinder& rFilePath,
00050 bool isCollective)
00051 {
00052 DynamicCellModelLoader* p_loader;
00053 std::string absolute_path = rFilePath.GetAbsolutePath();
00054
00055 if (!rFilePath.Exists())
00056 {
00057 EXCEPTION("Dynamically loadable cell model '" + absolute_path + "' does not exist.");
00058 }
00059
00060 size_t dot_position = absolute_path.find_last_of(".");
00061 if (dot_position == std::string::npos)
00062 {
00063 EXCEPTION("File does not have an extension: " + absolute_path);
00064 }
00065 std::string extension = absolute_path.substr(dot_position+1);
00066 if (extension == "cellml")
00067 {
00068
00069 size_t slash_position = absolute_path.find_last_of("/\\");
00070 assert(slash_position != std::string::npos);
00071 std::string folder = absolute_path.substr(0, slash_position+1);
00072 std::string leaf = absolute_path.substr(slash_position+1, dot_position-slash_position);
00073 std::string so_path = folder + "lib" + leaf + "so";
00074
00075 FileFinder so_file(so_path, RelativeTo::Absolute);
00076 if (!so_file.Exists() || rFilePath.IsNewerThan(so_file))
00077 {
00078 if (!isCollective)
00079 {
00080 EXCEPTION("Unable to convert .cellml to .so unless called collectively, due to possible race conditions.");
00081 }
00082 ConvertCellmlToSo(absolute_path, folder, leaf);
00083 }
00084
00085 p_loader = DynamicModelLoaderRegistry::Instance()->GetLoader(so_file);
00086 }
00087 else if (extension == "so")
00088 {
00089
00090 p_loader = DynamicModelLoaderRegistry::Instance()->GetLoader(rFilePath);
00091 }
00092 else
00093 {
00094 EXCEPTION("Unsupported extension '." + extension + "' of file '" + absolute_path + "'; must be .so or .cellml");
00095 }
00096
00097 return p_loader;
00098 }
00099
00100 void CellMLToSharedLibraryConverter::ConvertCellmlToSo(const std::string& rCellmlFullPath,
00101 const std::string& rCellmlFolder,
00102 const std::string& rModelLeafName)
00103 {
00104 std::string tmp_folder, build_folder;
00105 std::string old_cwd = GetCurrentWorkingDirectory();
00106 try
00107 {
00108
00109 if (PetscTools::AmMaster())
00110 {
00111
00112 std::stringstream folder_name;
00113 folder_name << "dynamic/tmp_" << getpid() << "_" << time(NULL);
00114 tmp_folder = std::string(ChasteBuildRootDir()) + mComponentName + "/" + folder_name.str();
00115 build_folder = std::string(ChasteBuildRootDir()) + mComponentName + "/build/" + ChasteBuildDirName() + "/" + folder_name.str();
00116 int ret = mkdir(tmp_folder.c_str(), 0700);
00117 EXCEPT_IF_NOT(ret == 0);
00118
00119 size_t dot_pos = rCellmlFullPath.rfind('.');
00120 std::string cellml_base = rCellmlFullPath.substr(0, dot_pos);
00121 EXPECT0(system, "cp " + cellml_base + "* " + tmp_folder);
00122
00123 std::string config_path = rCellmlFullPath.substr(0, rCellmlFullPath.length() - 7) + "-conf.xml";
00124 if (FileFinder(config_path, RelativeTo::Absolute).Exists())
00125 {
00126 EXPECT0(system, "cp " + config_path + " " + tmp_folder);
00127 }
00128
00129 EXPECT0(chdir, ChasteBuildRootDir());
00130
00131 EXPECT0(system, "scons --warn=no-all dyn_libs_only=1 build=" + ChasteBuildType() + " " + tmp_folder);
00132 EXCEPT_IF_NOT(FileFinder(tmp_folder + "/lib" + rModelLeafName + "so", RelativeTo::Absolute).Exists());
00133
00134 EXPECT0(chdir, old_cwd);
00135
00136 EXPECT0(system, "cp " + tmp_folder + "/lib" + rModelLeafName + "so " + rCellmlFolder);
00137 if (mPreserveGeneratedSources)
00138 {
00139
00140 EXPECT0(system, "cp " + build_folder + "/*.?pp " + rCellmlFolder);
00141 }
00142
00143 EXPECT0(system, "rm -r " + build_folder);
00144 EXPECT0(system, "rm -r " + tmp_folder);
00145 }
00146 }
00147 catch (Exception& e)
00148 {
00149 PetscTools::ReplicateException(true);
00150
00151 EXPECT0(system, "rm -rf " + build_folder);
00152 EXPECT0(system, "rm -r " + tmp_folder);
00153 EXPECT0(chdir, old_cwd);
00154 EXCEPTION("Conversion of CellML to Chaste shared object failed. Error was: " + e.GetMessage());
00155 }
00156
00157
00158 PetscTools::ReplicateException(false);
00159 }
00160
00161 void CellMLToSharedLibraryConverter::CreateOptionsFile(const OutputFileHandler& rHandler,
00162 const std::string& rModelName,
00163 const std::vector<std::string>& rArgs,
00164 const std::string& rExtraXml)
00165 {
00166 if (PetscTools::AmMaster())
00167 {
00168 out_stream p_optfile = rHandler.OpenOutputFile(rModelName + "-conf.xml");
00169 (*p_optfile) << "<?xml version='1.0'?>" << std::endl
00170 << "<pycml_config>" << std::endl;
00171 if (!rArgs.empty())
00172 {
00173 (*p_optfile) << "<command_line_args>" << std::endl;
00174 for (unsigned i=0; i<rArgs.size(); i++)
00175 {
00176 (*p_optfile) << "<arg>" << rArgs[i] << "</arg>" << std::endl;
00177 }
00178 (*p_optfile) << "</command_line_args>" << std::endl;
00179 }
00180 (*p_optfile) << rExtraXml << "</pycml_config>" << std::endl;
00181 p_optfile->close();
00182 }
00183 PetscTools::Barrier("CellMLToSharedLibraryConverter::CreateOptionsFile");
00184 }