@@ -20,6 +20,9 @@ import (
2020 "context"
2121 "fmt"
2222 "os"
23+ "regexp"
24+ "strconv"
25+ "strings"
2326
2427 "github.com/go-logr/logr"
2528
@@ -133,13 +136,190 @@ func (d *driverMgr) Clear(ctx context.Context) error {
133136}
134137
135138func (d * driverMgr ) prepareGCC (ctx context.Context ) error {
139+ log := logr .FromContextOrDiscard (ctx )
140+
141+ // Get OS type first to check if it's OpenShift
136142 osType , err := d .host .GetOSType (ctx )
143+ if err != nil {
144+ return fmt .Errorf ("failed to get OS type: %w" , err )
145+ }
146+
147+ // Check if OpenShift is detected - skip GCC setup for RHCOS/OpenShift
148+ if osType == constants .OSTypeOpenShift {
149+ log .V (1 ).Info ("RHCOS detected (OpenShift), skipping GCC setup" )
150+ return nil
151+ }
152+
153+ // Extract GCC version from /proc/version
154+ gccVersion , majorVersion , err := d .extractGCCInfo (ctx )
155+ if err != nil {
156+ return err
157+ }
158+ if gccVersion == "" {
159+ log .V (1 ).Info ("Could not extract GCC version from /proc/version" )
160+ return nil
161+ }
162+
163+ log .V (1 ).Info ("Kernel compiled with GCC version" , "version" , gccVersion , "major" , majorVersion )
164+
165+ // Install and configure GCC based on OS type
166+ gccBinary , kernelGCCVer , err := d .installGCCForOS (ctx , osType , majorVersion )
137167 if err != nil {
138168 return err
139169 }
140- //nolint:gocritic
170+
171+ // Set up alternatives for GCC binary
172+ return d .setupGCCAlternatives (ctx , gccBinary , kernelGCCVer )
173+ }
174+
175+ // extractGCCInfo extracts GCC version information from /proc/version
176+ func (d * driverMgr ) extractGCCInfo (ctx context.Context ) (string , int , error ) {
177+ log := logr .FromContextOrDiscard (ctx )
178+
179+ // Read /proc/version to extract GCC version
180+ procVersion , err := d .os .ReadFile ("/proc/version" )
181+ if err != nil {
182+ return "" , 0 , fmt .Errorf ("failed to read /proc/version: %w" , err )
183+ }
184+
185+ log .V (1 ).Info ("Kernel version info" , "proc_version" , string (procVersion ))
186+
187+ // Extract GCC version using regex
188+ gccVersion , err := d .extractGCCVersion (string (procVersion ))
189+ if err != nil {
190+ log .V (1 ).Info ("Could not extract GCC version from /proc/version" , "error" , err )
191+ return "" , 0 , nil // Not a fatal error, continue without GCC setup
192+ }
193+
194+ // Extract major version
195+ majorVersion , err := d .extractMajorVersion (gccVersion )
196+ if err != nil {
197+ return "" , 0 , fmt .Errorf ("failed to extract major version from %s: %w" , gccVersion , err )
198+ }
199+
200+ return gccVersion , majorVersion , nil
201+ }
202+
203+ // installGCCForOS installs GCC package based on OS type
204+ func (d * driverMgr ) installGCCForOS (ctx context.Context , osType string , majorVersion int ) (string , string , error ) {
141205 switch osType {
142- case "something" :
206+ case constants .OSTypeUbuntu :
207+ return d .installGCCUbuntu (ctx , majorVersion )
208+ case constants .OSTypeSLES :
209+ return d .installGCCSLES (ctx , majorVersion )
210+ case constants .OSTypeRedHat :
211+ return d .installGCCRedHat (ctx , majorVersion )
212+ default :
213+ return "" , "" , fmt .Errorf ("unsupported OS type: %s" , osType )
214+ }
215+ }
216+
217+ // installGCCUbuntu installs GCC for Ubuntu
218+ func (d * driverMgr ) installGCCUbuntu (ctx context.Context , majorVersion int ) (string , string , error ) {
219+ log := logr .FromContextOrDiscard (ctx )
220+ kernelGCCVer := fmt .Sprintf ("gcc-%d" , majorVersion )
221+
222+ log .V (1 ).Info ("Installing GCC for Ubuntu" , "package" , kernelGCCVer )
223+ _ , _ , err := d .cmd .RunCommand (ctx , "apt-get" , "-yq" , "update" )
224+ if err != nil {
225+ return "" , "" , fmt .Errorf ("failed to update apt packages: %w" , err )
143226 }
227+ _ , _ , err = d .cmd .RunCommand (ctx , "apt-get" , "-yq" , "install" , kernelGCCVer )
228+ if err != nil {
229+ return "" , "" , fmt .Errorf ("failed to install %s: %w" , kernelGCCVer , err )
230+ }
231+
232+ gccBinary := fmt .Sprintf ("/usr/bin/%s" , kernelGCCVer )
233+ return gccBinary , kernelGCCVer , nil
234+ }
235+
236+ // installGCCSLES installs GCC for SLES
237+ func (d * driverMgr ) installGCCSLES (ctx context.Context , majorVersion int ) (string , string , error ) {
238+ log := logr .FromContextOrDiscard (ctx )
239+ kernelGCCVerPackage := fmt .Sprintf ("gcc%d" , majorVersion )
240+ kernelGCCVerBin := fmt .Sprintf ("gcc-%d" , majorVersion )
241+
242+ log .V (1 ).Info ("Installing GCC for SLES" , "package" , kernelGCCVerPackage )
243+ _ , _ , err := d .cmd .RunCommand (ctx , "zypper" , "--non-interactive" , "install" , "--no-recommends" , kernelGCCVerPackage )
244+ if err != nil {
245+ return "" , "" , fmt .Errorf ("failed to install %s: %w" , kernelGCCVerPackage , err )
246+ }
247+
248+ gccBinary := fmt .Sprintf ("/usr/bin/%s" , kernelGCCVerBin )
249+ return gccBinary , kernelGCCVerBin , nil
250+ }
251+
252+ // installGCCRedHat installs GCC for RedHat
253+ func (d * driverMgr ) installGCCRedHat (ctx context.Context , majorVersion int ) (string , string , error ) {
254+ log := logr .FromContextOrDiscard (ctx )
255+ toolsetPackage := fmt .Sprintf ("gcc-toolset-%d" , majorVersion )
256+
257+ log .V (1 ).Info ("Checking for gcc-toolset availability" , "package" , toolsetPackage )
258+
259+ // Check if gcc-toolset is available
260+ _ , _ , err := d .cmd .RunCommand (ctx , "dnf" , "list" , "available" , toolsetPackage )
261+ if err == nil {
262+ // gcc-toolset version is available
263+ kernelGCCVer := fmt .Sprintf ("gcc-toolset-%d-gcc" , majorVersion )
264+ log .V (1 ).Info ("Installing gcc-toolset for RedHat" , "package" , toolsetPackage )
265+ _ , _ , err = d .cmd .RunCommand (ctx , "dnf" , "-q" , "-y" , "install" , toolsetPackage )
266+ if err != nil {
267+ return "" , "" , fmt .Errorf ("failed to install %s: %w" , toolsetPackage , err )
268+ }
269+ gccBinary := fmt .Sprintf ("/opt/rh/gcc-toolset-%d/root/usr/bin/gcc" , majorVersion )
270+ return gccBinary , kernelGCCVer , nil
271+ }
272+
273+ // Fall back to default gcc package
274+ log .V (1 ).Info ("gcc-toolset not available, using default gcc package" )
275+ kernelGCCVer := "gcc"
276+ _ , _ , err = d .cmd .RunCommand (ctx , "dnf" , "-q" , "-y" , "install" , "gcc" )
277+ if err != nil {
278+ return "" , "" , fmt .Errorf ("failed to install gcc: %w" , err )
279+ }
280+ gccBinary := "/usr/bin/gcc"
281+ return gccBinary , kernelGCCVer , nil
282+ }
283+
284+ // setupGCCAlternatives sets up GCC alternatives
285+ func (d * driverMgr ) setupGCCAlternatives (ctx context.Context , gccBinary , kernelGCCVer string ) error {
286+ log := logr .FromContextOrDiscard (ctx )
287+ altGCCPrio := 200
288+
289+ log .V (1 ).Info ("Setting up GCC alternatives" , "gcc_binary" , gccBinary , "priority" , altGCCPrio )
290+ _ , _ , err := d .cmd .RunCommand (ctx , "update-alternatives" , "--install" , "/usr/bin/gcc" , "gcc" , gccBinary , strconv .Itoa (altGCCPrio ))
291+ if err != nil {
292+ return fmt .Errorf ("failed to set up GCC alternatives: %w" , err )
293+ }
294+
295+ log .Info ("Set GCC for driver compilation, matching kernel compiled version" , "version" , kernelGCCVer )
144296 return nil
145297}
298+
299+ // extractGCCVersion extracts GCC version from /proc/version string
300+ func (d * driverMgr ) extractGCCVersion (procVersion string ) (string , error ) {
301+ // Regex to match gcc version pattern: gcc followed by optional non-digit characters and then version number
302+ re := regexp .MustCompile (`(?i)gcc[^0-9]*([0-9]+\.[0-9]+\.[0-9]+)` )
303+ matches := re .FindStringSubmatch (procVersion )
304+
305+ if len (matches ) < 2 {
306+ return "" , fmt .Errorf ("no GCC version found in /proc/version" )
307+ }
308+
309+ return matches [1 ], nil
310+ }
311+
312+ // extractMajorVersion extracts the major version number from a version string like "11.5.0"
313+ func (d * driverMgr ) extractMajorVersion (version string ) (int , error ) {
314+ parts := strings .Split (version , "." )
315+ if len (parts ) == 0 {
316+ return 0 , fmt .Errorf ("invalid version format: %s" , version )
317+ }
318+
319+ major , err := strconv .Atoi (parts [0 ])
320+ if err != nil {
321+ return 0 , fmt .Errorf ("failed to parse major version from %s: %w" , version , err )
322+ }
323+
324+ return major , nil
325+ }
0 commit comments