Besoin d’aide pour tester un programme multi-plateformes

J’en appelle aux bonnes âmes…

Le problème exposé dans ce sujet a été résolu.

Bonjour à tous.

Dans ma quête de la programmation système en Rust, je m’essaye à quelque chose de certainement pas très utile, mais en tout cas très amusant : écrire en Rust quelques fonctions de la bibliothèque standard du C, naturellement sans s’appuyer sur la libc présente sur le système.

J’ai fait un certain nombre de tests, et ça marche nickel, mais je n’ai fait les tests que sur ma machine, c’est-à-dire sous un Linux 64 bits. J’en appelle aux bonnes âmes de ce forum, si vous avez un compilateur Rust Nightly sur une des plate-formes suivantes, pourriez-vous essayer de compiler mon code, me dire si les résultats sont corrects, et le cas échéant, me faire une remontée de bogues ?

  • OS X 64 bits sur un processeur x86_64. (Fait, merci d3m0t3p.)
  • N’importe quel BSD 64 bits sur un processeur x86_64.
  • OpenSolaris 64 bits sur un processeur x86_64.

Merci d’avance aux volontaires ! :)

Tout d’abord, un fichier syscall.rs, suivi d’un fichier x86_64.rs, à compiler au moyen de rustc -O syscall.rs.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#![crate_type="rlib"]
#![crate_name = "rsc"]
#![feature(asm)]
#![no_std]

#[cfg(target_arch = "x86_64")]
#[macro_use]
mod x86_64;

#[cfg(target_arch = "x86_64")]
pub use x86_64::*;

#[no_mangle]
pub extern fn getpid() -> i32   {
    syscall!(Syscall::GetPID) as i32
}

#[cfg(not(target_os = "solaris"))]
#[no_mangle]
pub extern fn getpgid(pid : i32) -> i32 {
    syscall!(Syscall::GetPGID, pid) as i32
}

#[cfg(target_os = "solaris")]
#[no_mangle]
pub extern fn getpgid(pid : i32) -> i32 {
    syscall!(Syscall::PGrpSys, 4, pid) as i32
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
macro_rules! syscall    {
    ($sysnum:expr) => {{
        let ret : u64;

        unsafe  {
            asm!("mov rax, $1\n\t\
                  syscall"
                : "={rax}"(ret)
                : "i"($sysnum as u64)
                : "rcx", "r11", "memory"
                : "intel", "volatile"
            );
        }

        ret
    }};
    ($sysnum:expr, $a1:expr) => {{
        let ret : u64;

        unsafe  {
            asm!("mov rax, $1\n\t\
                  syscall"
                : "={rax}"(ret)
                : "i"($sysnum as u64), "{rdi}"(($a1) as u64)
                : "rcx", "r11", "memory"
                : "intel", "volatile"
            );
        }

        ret
    }};
    ($sysnum:expr, $a1:expr, $a2:expr) => {{
        let ret : u64;

        unsafe  {
            asm!("mov rax, $1\n\t\
                  syscall"
                : "={rax}"(ret)
                : "i"($sysnum as u64), "{rdi}"(($a1) as u64),
                    "{rsi}"(($a2) as u64)
                : "rcx", "r11", "memory"
                : "intel", "volatile"
            );
        }

        ret
    }};
    ($sysnum:expr, $a1:expr, $a2:expr, $a3:expr) => {{
        let ret : u64;

        unsafe  {
            asm!("mov rax, $1\n\t\
                  syscall"
                : "={rax}"(ret)
                : "i"($sysnum as u64), "{rdi}"(($a1) as u64),
                    "{rsi}"(($a2) as u64), "{rdx}"(($a3) as u64)
                : "rcx", "r11", "memory"
                : "intel", "volatile"
            );
        }

        ret
    }};
    ($sysnum:expr, $a1:expr, $a2:expr, $a3:expr,
        $a4:expr) =>
    {{
        let ret : u64;

        unsafe  {
            asm!("mov rax, $1\n\t\
                  syscall"
                : "={rax}"(ret)
                : "i"($sysnum as u64), "{rdi}"(($a1) as u64),
                    "{rsi}"(($a2) as u64), "{rdx}"(($a3) as u64),
                    "{r10}"(($a4) as u64)
                : "rcx", "r11", "memory"
                : "intel", "volatile"
            );
        }

        ret
    }};
    ($sysnum:expr, $a1:expr, $a2:expr, $a3:expr,
        $a4:expr, $a5:expr) =>
    {{
        let ret : u64;

        unsafe  {
            asm!("mov rax, $1\n\t\
                  syscall"
                : "={rax}"(ret)
                : "i"($sysnum as u64), "{rdi}"(($a1) as u64),
                    "{rsi}"(($a2) as u64), "{rdx}"(($a3) as u64),
                    "{r10}"(($a4) as u64), "{r8}"(($a5) as u64)
                : "rcx", "r11", "memory"
                : "intel", "volatile"
            );
        }

        ret
    }};
    ($sysnum:expr, $a1:expr, $a2:expr, $a3:expr,
        $a4:expr, $a5:expr, $a6:expr) =>
    {{
        let ret : u64;

        unsafe  {
            asm!("mov rax, $1\n\t\
                  syscall"
                : "={rax}"(ret)
                : "i"($sysnum as u64), "{rdi}"(($a1) as u64),
                    "{rsi}"(($a2) as u64), "{rdx}"(($a3) as u64),
                    "{r10}"(($a4) as u64), "{r8}"(($a5) as u64),
                    "{r9}"(($a6) as u64)
                : "rcx", "r11", "memory"
                : "intel", "volatile"
            );
        }

        ret
    }};
}

#[cfg(target_os = "linux")]
pub enum Syscall    {
    GetPID  = 0x27,
    GetPGID = 0x79,
}

#[cfg(target_os = "macos")]
pub enum Syscall    {
    GetPID  = 0x2000014,
    GetPGID = 0x2000097,
}

#[cfg(any(target_os = "bitrig",
          target_os = "dragonfly",
          target_os = "freebsd",
          target_os = "netbsd",
          target_os = "openbsd"))]
pub enum Syscall    {
    GetPID  = 0x14,
    GetPGID = 0xcf,
}

#[cfg(target_os = "solaris")]
pub enum Syscall    {
    GetPID  = 0x14,
    PGrpSys = 0x27,
  /*
       * subcodes:
       *  getpgrp()         :: syscall(39,0)
       *  setpgrp()         :: syscall(39,1)
       *  getsid(pid)       :: syscall(39,2,pid)
       *  setsid()          :: syscall(39,3)
       *  getpgid(pid)      :: syscall(39,4,pid)
       *  setpgid(pid,pgid) :: syscall(39,5,pid,pgid)
       */
}

Et pour tester si on obtient les bons résultats, un fichier getpid.rs, à compiler comme rustc -O -L. getpid.rs.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#![feature(libc)]

extern crate libc;
extern crate rsc;

fn main()   {
    let pid_libc = unsafe { libc::getpid() };
    let pid_rsc  = rsc::getpid();
    assert_eq!(pid_libc, pid_rsc);
}

Et le meilleur dans l’histoire, c’est que vous pouvez vous en servir depuis un programme en C ! Il vous faudra juste renommer librsc.rlib en librsc.a et compiler avec le bonnes options. Et le nom des fonctions risque d’entrer en conflit avec celles de la libc, donc n’hésitez pas à rajouter un rs_ devant leur nom dans le code Rust de départ.

+1 -0

Je dis ça totalement sans savoir.

Il n'y a pas moyen d'utiliser une machine virtuelle ? (Au moins pour BSD et OpenSolaris).


Je comprend tout à fais. N’empêche, c'est l'occasion de découvrir d'autres systèmes et de se former à la virtualisation :D

+0 -0

Stricto sensu, ça devrait fonctionner, mais comme je n’ai jamais monté d’OS alternatif sur une machine virtuelle, ni jamais utilisé aucun de ces trois OS, et que ce n’est pas vraiment important, c’est quand même plus simple de demander si quelqu’un n’aurait pas déjà de quoi faire les tests.

Et accessoirement, ça permet de montrer du code vraiment bas niveau, pour ceux qui s’intéressent à Rust. :)

+0 -0

Salut,

Je suis disposé à effectuer le test sous OpenBSD (5.9 amd64), maintenant, la compilation des sources de « nightly » foire chez moi avec le message suivant.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
cfg: version 1.13.0
cfg: build triple x86_64-unknown-openbsd
cfg: host triples x86_64-unknown-openbsd
cfg: target triples x86_64-unknown-openbsd
cfg: host for x86_64-unknown-openbsd is x86_64
cfg: os for x86_64-unknown-openbsd is unknown-openbsd
cfg: no good valgrind for x86_64-unknown-openbsd
cfg: using CC=egcc (CFG_CC)
cfg: using CXX=eg++ (CFG_CXX)
cfg: disabling valgrind run-pass tests
cfg: disabling unstable features (CFG_DISABLE_UNSTABLE_FEATURES)
fetch: x86_64-unknown-openbsd/stage0/bin/rustc
downloading https://static.rust-lang.org/dist/2016-07-06/rustc-beta-x86_64-unknown-openbsd.tar.gz.sha256 to /tmp/tmpd3bdiI.sha256
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100   334    0   334    0     0   1159      0 --:--:-- --:--:-- --:--:--  1805
downloading https://static.rust-lang.org/dist/2016-07-06/rustc-beta-x86_64-unknown-openbsd.tar.gz to /tmp/tmpbbmQMC
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100   327    0   327    0     0   1341      0 --:--:-- --:--:-- --:--:--  2069
verifying /tmp/tmpbbmQMC
removing /tmp/tmpd3bdiI.sha256
removing /tmp/tmpbbmQMC
Traceback (most recent call last):
  File "/tmp/rustc-nightly/src/etc/get-stage0.py", line 46, in <module>
    main(sys.argv[1])
  File "/tmp/rustc-nightly/src/etc/get-stage0.py", line 34, in main
    bootstrap.get(url, dst)
  File "/tmp/rustc-nightly/src/bootstrap/bootstrap.py", line 42, in get
    if not verify(temp_path, sha_path, True):
  File "/tmp/rustc-nightly/src/bootstrap/bootstrap.py", line 74, in verify
    expected, _ = f.readline().split()
ValueError: too many values to unpack
/tmp/rustc-nightly/mk/stage0.mk:17: recipe for target 'x86_64-unknown-openbsd/stage0/bin/rustc' failed
gmake: *** [x86_64-unknown-openbsd/stage0/bin/rustc] Error 1

Une idée concernant la source de l'erreur ?

+0 -0

Ouh le vilain trou noir dans leur CI !

/troll

PS : Plus sérieusement c'est vraiment étonnant de la part de Rust, sachant que ce projet est à l'origine de l'un des gatekeepers les plus connus (Bors), et qu'en principe celui-ci ne laisse passer aucun commit qui ne builde pas.

J'en déduis qu'ils ne testent pas la compilation dans les mêmes conditions que le déploiement sur tous les OS supportés, ce qui est d'autant plus surprenant de la part de mozilla qui est pourtant censé en connaître un rayon sur l'industrialisation.

+0 -0

Merci à d3m0t3p qui m’a fait les tests pour OS X. La bonne nouvelle, c’est que ça passe impec.

@Taurre : le souci vient du fait que OpenBSD est un OS du Tier 3, c’est-à-dire avec un support très limité.

De manière plus spécifique, rustc étant écrit en Rust, il a besoin d’un compilateur préexistant pour se compiler (le stage0). Pour ce faire, s’il n’y en a pas d’installé sur ta machine, il va essayer d’aller en récupérer un sur le site de Rust. Sauf que visiblement, il n’y a pas de rustc pré-compilé pour OpenBSD…

Il semblerait qu’il existe un port de Rust 1.9, qui pourrait peut-être servir de base pour compiler la nouvelle version, mais je ne peux pas jurer que 1.9 soit assez récent pour compiler 1.13.

+0 -0

Alors apparemment, il n’utilise pas automatiquement le compilateur Rust présent, il faut passer les arguments --enable-local-rust et --local-rust-root= à ./configure. Ensuite, si malgré ça, ça ne fonctionne toujours pas, tu devrais pouvoir installer rustup qui, lui,est censé savoir faire toute la magie nécessaire.

Et si après tout ça tu arrives finalement à installer un rustc à jour chez toi, tu auras bien mérité de mettre à jour le port officiel d’OpenBSD. :D

+0 -0

Effectivement l'utilisation de l'option --enable-local-rust m'a permis de poursuivre la compilation. Par contre, comme le compilateur disponible dans les paquets et les ports est en version 1.6, il ne m'a pas été possible de la terminer… Bref, je pense que c'est râpé pour tester sous OpenBSD. :-°

Par contre, si tu veux, je peux te dire si la suite d'instructions en Assembleur fonctionne. :p

+0 -0

Ah oui non mais forcément, si la version est antédiluvienne, aussi, j’abandonne… >_< Merci pour ta patience, en tout cas.

Hum, oui, pourquoi pas. Après, qu’elle renvoie quelque chose, ça, c’est assuré. La question, c’est de savoir si ça renvoie bien la même chose que la fonction C équivalente. :D

+0 -0

Ah oui non mais forcément, si la version est antédiluvienne, aussi, j’abandonne… >_< Merci pour ta patience, en tout cas.

Dominus Carnufex

En même temps il faut s'y attendre de la part d'une distribution dont l'une des priorités est la sécurité : par définition le processus de release d'une telle distribution est incompatible avec l'utilisation de ressources en version "nightly build". C'est la même chose pour toutes les technos, d'ailleurs, qu'il s'agisse de features de GCC (avoir la bonne version pour utiliser C++11 sur une Red Hat 5.7, par exemple), ou encore de distributions Python (CentOS 6 en est encore à Python 2.6), et je suis certain qu'il y a encore une foultitude d'autres exemples dans le même cas.

C'est l'éternel compromis du release engineering : avoir des technos fraîches vs. supporter un maximum de plateformes. Et c'est un cauchemar pour les développeurs qui sont restreints à ne pas utiliser les dernières features de-la-mort de leurs langages tant qu'ils doivent supporter un système d'exploitation historique.

Edit : je ne comprends pas ton -1. Mais peu importe.

+1 -1

Ah oui non mais forcément, si la version est antédiluvienne, aussi, j’abandonne… >_< Merci pour ta patience, en tout cas.

Dominus Carnufex

Pour remettre les choses dans leur contexte, Rust 1.6 date du 26 janvier 2016. Personnellement, je suis surpris de trouver une version aussi récente de Rust dans OpenBSD, quand j'avais joué avec (vers 2008 - 2009), c'était parfaitement illusoire de trouver des versions aussi récentes (8 mois) de logiciels directement dans les ports.

PS : c'est le compromis dont parle nohar qui fait aussi que, par exemple, Docker n'est pas inclus dans les packages « standard » de Debian 8 Jessie. Debian ne voulait pas un logiciel qui change aussi souvent, et Docker ne voulait pas maintenir une même version aussi longtemps. Bref, c'est un cas fréquent dans le monde de l'industrie, surtout quand tu as des contraintes de stabilité fortes.

Edit : je ne comprends pas ton -1. Mais peu importe.

Je t’ai mis un -1 parce que ta réponse est parfaitement hors-sujet dans le contexte.

Rust publie une nouvelle version toutes les 6 semaines, je sais très bien que la 1.6 a moins d’un an, ce qui est tout à fait honorable à l’échelle d’un système d’exploitation. Sur mon Linux Mint, si j’utilisais les paquets officiels, j’aurais la 1.7, par exemple.

Mais ce n’est pas la question ici. La question ici, c’est de savoir si Taurre peut compiler la version 1.13 Nightly chez lui sans que ça lui prenne une semaine. Le problème étant que, en théorie, chaque version doit être compilée avec la précédente pour qu’il n’y ait pas d’erreur.

Peut-être qu’avec de la chance, on peut se permettre de sauter de 2 versions en 2 versions. Mais quand on part de la 1.6 pour arriver à la 1.13, sans être certains qu’on va pouvoir prendre des raccourcis, ce n’est même pas la peine.

Parce que, dans le contexte qui est le nôtre d’essayer de compiler rustc 1.13, la version 1.6 est de facto antédiluvienne.

+0 -0

Dans le contexte qui est le tien, tester un code qui dépend de la nightly build de Rust sur OpenBSD lève un problème plus large : ton code n'est pas fait pour supporter OpenBSD, puisqu'il me tourne pas sur la version officiellement supportée par OpenBSD.

Ma remarque est donc parfaitement justifiée : tu dois proposer un code qui compile sous tous les OS visés sans avoir besoin de compiler le compilateur, sans quoi tu ne peux pas considérer que ton code supporte l'OS en question.

+2 -1

Aucun OS n’utilise officiellement la version Nightly. Aucun. Pourtant, il faut Nightly pour compiler la bibliothèque standard de Rust. Selon ta logique, donc, la bibliothèque standard du langage elle-même n’est faite pour supporter absolument aucun OS.

Conclusion : tu racontes juste de la merde, en fait.

+0 -7

Aucun OS n’utilise officiellement la version Nightly. Aucun. Pourtant, il faut Nightly pour compiler la bibliothèque standard de Rust.

Ah bon ? Moi qui croyais bêtement que tous les OS packageaient sa bibliothèque standard dans une version compatible avec celle du compilateur qu'ils supportent, de la même manière qu'ils le font pour à peu près 100% des langages officiellement supportés…

J'ai dû me tromper. D'ailleurs, la commande suivante est probablement un énorme poisson d'avril de la part de mon système d'exploitation :

1
2
3
13:39 arnaud@merlyn% apt-cache search rust |grep standard          
libstd-rust-1.7 - Rust standard libraries
libstd-rust-dev - Rust standard libraries - development files

Je te remercie pour cette démonstration, en toute humilité, de ta parfaite maîtrise du sujet, et j'en profite pour saluer tes qualités de diplomate-né. Sur ce, je cours réapprendre mon métier. :)

+2 -1

Ça ne te ferait effectivement pas de mal d’apprendre à la fermer quand manifestement tu ne sais pas de quoi tu parles. Je vais essayer de te l’expliquer avec des mots simples, mais je garantis pas d’être diplomate.

En Rust, un certain nombre de fonctionnalités ne sont pas disponibles par défaut. Par exemple, pour utiliser les fonctions permettant d’allouer et désallouer manuellement de la mémoire (l’équivalent de malloc et free), il faut explicitement activer la fonctionnalité alloc, ce qui se fait en ajoutant la ligne suivante en haut de ton code source.

1
#![feature(alloc)]

Pour plus de détails sur ce feature gate, ça se passe ici.

Mais ce n’est pas tout : encore faut-il que le compilateur accepte que tu utilises #![feature(…)]. Le code qui gère cette autorisation ou non se trouve ici. Comme tu le vois, il y a une variable d’environnement CFG_DISABLE_UNSTABLE_FEATURES qui gère l’autorisation ou non.

Sauf que cette variable est écrite en dur dans ton compilateur. Un fois que rustc est compilé, tu ne peux plus la changer. Et les exécutables des versions Stable et Beta interdisent l’utilisation de #![feature(…)], seuls les exécutables de la version Nightly l’autorisent.

Or, une des principales fonctionnalités protégées par le feature gate, c’est la possibilité de ne pas utiliser la bibliothèque standard de Rust, le fameux #![no_std] qui se trouve à la quatrième ligne de mon code source. Et pour des raisons évidentes, cette fonctionnalité est indispensable pour le code source même de la bibliothèque standard.

Ce qui signifie que pour compiler la bibliothèque standard de Rust, il te faut un compilateur Nightly. Même si, évidemment, une fois qu’elle est compilée, il est tout à fait possible de la distribuer avec le compilateur stable.

Et vois-tu, il en va de même avec mon code. Pour le compiler, il faut impérativement une version Nightly. En revanche, une fois compilé sous forme d’un .so ou d’un .rlib, n’importe quel programme Rust peut l’utiliser, quelle que soit la variante de son compilateur.

+0 -0

Je te remercie pour cette explication : si tu avais donné cette info (que juste personne ne peut inventer) dès le départ, au lieu de te montrer insultant (à ce propos je vais gentiment laisser couler la première phrase tout à fait puante de ton post, mais c'est la dernière fois en ce qui me concerne, et là c'est le modérateur qui parle) et de me prendre de haut avec un sophisme, on aurait gagné beaucoup de temps.

Du reste, ne t'est-il pas tout bêtement possible de proposer un binaire cross-compilé à lancer pour tester que ça marche ? Ça simplifierait grandement la démarche.

+2 -0

Aucun OS n’utilise officiellement la version Nightly. Aucun. Pourtant, il faut Nightly pour compiler la bibliothèque standard de Rust. Selon ta logique, donc, la bibliothèque standard du langage elle-même n’est faite pour supporter absolument aucun OS.

Conclusion : tu racontes juste de la merde, en fait.

+

Ça ne te ferait effectivement pas de mal d’apprendre à la fermer quand manifestement tu ne sais pas de quoi tu parles. Je vais essayer de te l’expliquer avec des mots simples, mais je garantis pas d’être diplomate.

C'est ce que j'appelle franchir allègrement la ligne. Et comme je ne fais aucune exception face à ce genre de posts, j'applique donc la sanction classique : bannissement temporaire de 3 jours.

Rien ne justifie un comportement aussi déplacé.

+7 -2
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte