1#!/usr/bin/python
2# -*- coding: utf-8 -*-
3# ***************************************************************************
4# *   Copyright (c) 2015 by Pierre-Henri WUILLEMIN                          *
5# *   {prenom.nom}_at_lip6.fr                                               *
6# *                                                                         *
7# *   "act" is free software; you can redistribute it and/or modify         *
8# *   it under the terms of the GNU General Public License as published by  *
9# *   the Free Software Foundation; either version 2 of the License, or     *
10# *   (at your option) any later version.                                   *
11# *                                                                         *
12# *   This program is distributed in the hope that it will be useful,       *
13# *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
14# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
15# *   GNU General Public License for more details.                          *
16# *                                                                         *
17# *   You should have received a copy of the GNU General Public License     *
18# *   along with this program; if not, write to the                         *
19# *   Free Software Foundation, Inc.,                                       *
20# *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
21# **************************************************************************
22import platform
23import multiprocessing
24import os
25
26from .configuration import cfg
27from .multijobs import execCde
28from .utils import trace, setifyString, critic, notif
29
30
31def getCmake(current, target):
32  line = cfg.cmake + " ../.."  # we are in build/[release|target]
33
34  line += " -DCMAKE_EXPORT_COMPILE_COMMANDS=ON "  # for clang-tidy
35
36  if current["mode"] == "release":
37    line += " -DCMAKE_BUILD_TYPE=RELEASE"
38  else:
39    line += " -DCMAKE_BUILD_TYPE=DEBUG"
40
41  if current["withSQL"]:
42    line += " -DUSE_NANODBC=ON"
43  else:
44    line += " -DUSE_NANODBC=OFF"
45
46  line += " -DCMAKE_INSTALL_PREFIX=" + '"' + current["destination"] + '"'
47
48  if current["verbose"]:
49    line += " -DCMAKE_VERBOSE_MAKEFILE=ON"
50  else:
51    line += " -DCMAKE_VERBOSE_MAKEFILE=OFF"
52
53  if current["static_lib"]:
54    line += " -DBUILD_SHARED_LIBS=OFF"
55  else:
56    line += " -DBUILD_SHARED_LIBS=ON"
57
58  if current["coverage"]:
59    line += " -DGUM_COVERAGE=ON"
60  else:
61    line += " -DGUM_COVERAGE=OFF"
62
63  line += " -DBUILD_ALL=OFF"
64  for module in setifyString(current["modules"]):
65    line += " -DBUILD_" + module + "=ON"
66
67  if current["fixed_seed"]:
68    line += " -DGUM_RANDOMSEED=" + cfg.fixedSeedValue
69  else:
70    line += " -DGUM_RANDOMSEED=0"
71
72  if target != "pyAgrum":
73    line += " -DBUILD_PYTHON=OFF"
74  else:
75    line += " -DBUILD_PYTHON=ON"
76
77
78  if current["python3lib"] != "":
79    line += " -DPYTHON_LIBRARY=" + current["python3lib"]
80
81  if current["python3include"] != "":
82    line += " -DPYTHON_INCLUDE_DIR=" + current["python3include"]
83
84  if platform.system() == "Windows":
85    if current["windows"] == "mvsc19":
86      line += ' -G "Visual Studio 16 2019" -A x64'
87    elif current["windows"] == "mvsc19_32":
88      line += ' -G "Visual Studio 16 2019" -A Win32'
89    elif current["windows"] == "mvsc17":
90      line += ' -G "Visual Studio 15 2017 Win64"'
91    elif current["windows"] == "mvsc17_32":
92      line += ' -G "Visual Studio 15 2017"'
93    elif current["windows"] == "mvsc15":
94      line += ' -G "Visual Studio 14 2015 Win64"'
95    elif current["windows"] == "mvsc15_32":
96      line += ' -G "Visual Studio 14 2015"'
97    elif current["windows"] == "mingw64":
98      line += ' -G "MinGW Makefiles"'
99
100  return line
101
102
103def buildCmake(current, target):
104  line = getCmake(current, target)
105  execFromLine(current, line)
106
107
108def getMake(current, target):
109  if platform.system() == "Windows":
110    return getForMsBuildSystem(current, target)
111  else:
112    return getForMakeSystem(current, target)
113
114
115def getNbrOfJobs(jobrequest):
116  # number of jobs
117  nbrProc = multiprocessing.cpu_count()
118  if nbrProc == 1:
119    return "1"
120  else:
121    if jobrequest == "except1":
122      return str(nbrProc - 1)
123    elif jobrequest == "half":
124      return str(int(nbrProc / 2))  # >=1
125    elif jobrequest == "halfexcept1":
126      if nbrProc <= 3:
127        return "1"
128      else:
129        return str(int(nbrProc / 2) - 1)
130    elif jobrequest == "all":
131      return str(nbrProc)
132    else:
133      try:
134        nbrJob = int(jobrequest)
135        if nbrJob < 1:
136          nbrJob = 1
137        if nbrJob > nbrProc:
138          return str(nbrProc)
139        else:
140          return str(nbrJob)
141      except ValueError:
142        notif("Option '-j "+jobrequest+"' is invalid. Using '-j halfexcept1'.")
143        return getNbrOfJobs("halfexcept1")
144
145
146def getForMsBuildSystem(current, target):
147  if cfg.msbuild is None:
148    critic("MsBuild not found")
149  else:
150    nbrJobs = getNbrOfJobs(current['jobs'])
151    notif("Compilation using ["+nbrJobs+"] jobs.")
152    if current["action"] == "test":
153      if target == "aGrUM":
154        line = cfg.msbuild + ' agrum.sln /t:gumTest /p:Configuration="Release"'
155      elif target == "pyAgrum":
156        line = cfg.msbuild + ' agrum.sln /t:_pyAgrum /p:Configuration="Release"'
157      else:  # if target!= "pyAgrum":
158        critic(
159            "Action '" + current[
160                "action"] + "' not treated for target '" + target + "' for now in windows strange world.")
161    elif current["action"] == "install":
162      line = cfg.msbuild + ' INSTALL.vcxproj /p:Configuration="Release"'
163    elif current["action"] == "lib":
164      line = cfg.msbuild + ' INSTALL.vcxproj /p:Configuration="Release"'
165    else:
166      critic("Action '" + current["action"] +
167             "' not treated for now in windows weird world.")
168    line += ' /p:BuildInParallel=true /maxcpucount:' + nbrJobs
169  return line
170
171
172def getForMakeSystem(current, target):
173  line = cfg.make
174
175  nbrJobs = str(getNbrOfJobs(current['jobs']))
176  notif("Compilation using  ["+nbrJobs+"] jobs.")
177
178  if current["action"] == "test":
179    if target == "aGrUM":
180      line += " gumTest"
181    elif target != "pyAgrum":
182      critic("Action '" + current["action"] +
183             "' not treated for target '" + target + "'.")
184  elif current["action"] == "install":
185    line += " install"
186  elif current["action"] == "uninstall":
187    line += " uninstall"
188  elif current["action"] == "lib":
189    pass
190  elif current["action"] == "doc":
191    line += " doc"
192  else:
193    critic("Action '" + current["action"] + "' not treated for now")
194
195  line += " -j " + nbrJobs
196
197  if target == "pyAgrum":
198    line += " -C wrappers/pyAgrum"
199
200  return line
201
202
203def buildMake(current, target):
204  line = getMake(current, target)
205  execFromLine(current, line)
206
207
208def getPost(current, target):
209  if current["action"] == "test":
210    if target == "aGrUM":
211      if cfg.os_platform == "win32":
212        if current["windows"] == "mingw64":
213          line = "src\\gumTest.exe"
214        else:
215          line = "src\\Release\\gumTest.exe"  # debug or release create Release folder
216      else:
217        line = "src/gumTest"
218      return line, True
219    elif target == "pyAgrum":
220      if current['tests'] == 'quick':
221        gumTest = "gumTest.py"
222      elif current['tests'] == 'all':  # all is with NOTEBOOKStest
223        gumTest = "gumTest.py all"
224      else:
225        critic("Only [-t all] or [-t quick] for testing pyAgrum.")
226
227      if cfg.os_platform == "win32":
228        line = 'copy /Y "wrappers\pyAgrum\Release\_pyAgrum.pyd" "wrappers\pyAgrum\." & ' + \
229            cfg.python + " ..\\..\\wrappers\\pyAgrum\\testunits\\" + gumTest
230      else:
231        line = cfg.python + " ../../wrappers/pyAgrum/testunits/" + gumTest
232      line += " " + current['mode']
233      return line, True
234  return "", False
235
236
237def buildPost(current, target):
238  line, checkRC = getPost(current, target)
239  if line != "":
240    execFromLine(current, line, checkRC)
241
242
243def execFromLine(current, line, checkRC=True):
244  trace(current, line)
245  if not current['dry_run']:
246    rc = execCde(line, current)
247    if checkRC:
248      if rc > 0:
249        critic(f"Received error {rc}", rc=rc)
250